Robozombie
Robozombie

Reputation: 37

Passing a state from a Child to the App component With React Context (Image editor App)

I'm building out this simple image editor, where you can upload an image from your drive and then filter it with various css properties. The file upload part is in a component called FileUpload, and is a child of the App. My problem is that i need a state of the FileUpload to be accesible within the App.js to render the picture. This is the return of the App component:

return (
    <div className="container">
      <div className="file-upload">
        <FileUpload />
      </div>

      <div style={getImageStyle()} className="main-image" />
      <div className="sidebar">
        {options.map((option, index) => {
          return (
            <SidebarItem
              key={index}
              name={option.name}
              active={index === selectedOptionIndex}
              handleClick={() => setSelectedOptionIndex(index)}
            />
          );
        })}
      </div>
      <Slider
        min={selectedOption.range.min}
        max={selectedOption.range.max}
        value={selectedOption.value}
        handleChange={handleSliderChange}
      />
    </div>
  );

Now i need a state that is inside the FileUpload component:

 const [file, setFile] = useState("");
  const [filename, setFilename] = useState("Choose File");
  const [uploadedFile, setUploadedFile] = useState({});
  const [message, setMessage] = useState("");
  const [uploadPercentage, setUploadPercentage] = useState(0);

  const onChange = (e) => {
    setFile(e.target.files[0]);
    setFilename(e.target.files[0].name);
  };

  const onSubmit = async (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append("file", file);

    try {
      const res = await axios.post("/upload", formData, {
        headers: {
          "Content-Type": "multipart/form-data",
        },
        onUploadProgress: (progressEvent) => {
          setUploadPercentage(
            parseInt(
              Math.round((progressEvent.loaded * 100) / progressEvent.total)
            )
          );

          // Clear percentage
          setTimeout(() => setUploadPercentage(0), 10000);
        },
      });

      const { fileName, filePath } = res.data;

      setUploadedFile({ fileName, filePath });

      setMessage("File Uploaded");
    } catch (err) {
      if (err.response.status === 500) {
        setMessage("There was a problem with the server");
      } else {
        setMessage(err.response.data.msg);
      }
    }
  };

  return (
    <Fragment>
      <form onSubmit={onSubmit}>
        <div>
          <input
            type="file"
            className="custom-file-input"
            id="customFile"
            onChange={onChange}
          />
          <label className="custom-file-label" htmlFor="customFile">
            {filename}
          </label>
        </div>

        <Progress percentage={uploadPercentage} />

        <input
          type="submit"
          value="Upload"
          className="btn btn-primary btn-block mt-4"
        />
      </form>
      {uploadedFile ? (
        <div className="row mt-5">
          <div className="col-md-6 m-auto">
            <h3 className="text-center">{uploadedFile.fileName}</h3>
            <img style={{ width: "100%" }} src={uploadedFile.filePath} alt="" />
          </div>
        </div>
      ) : null}
    </Fragment>
  );
};

Now i would need the uploadedFile state to be accesible within the App because i need that file to set the background image of the div <div style={getImageStyle()} className="main-image" /> Would be possible to use useContext, or i should move all the state and logic inside the parent App? Thank you very much for the help

Upvotes: 0

Views: 38

Answers (1)

user103716
user103716

Reputation: 312

what about declaring a prop in FileUpload which is a callback called when the file is uploaded and passes the file back to App?

so something like <FileUpload onComplete={fileUploadedHandler}/>?

Upvotes: 0

Related Questions