Search code examples
reactjsreact-dropzone

React change state next component


I must create upload files unique component for input type file, for it i use react-dropzone library with drag and drop and use this component 4 time in page. Initial Initially, besides the first component, other components must be disabled, but after loading the file, the next component must change state to disable = {true}.How do I properly implement the logic using useState?

sandbox

UploadFile.js

const UploadFile = ({ visible }) => {
  const [active, setActive] = useState(false);

  useEffect(() => {
    if (!visible) {
      setActive(true);
    }
  }, [visible]);

  console.log(visible);

  const { getRootProps, getInputProps, open, acceptedFiles } = useDropzone({
    noClick: true,
    noKeyboard: true,
    disabled: active
  });

  const files = acceptedFiles.map((file) => (
    <li key={file.path}>
      {file.path} - {file.size} bytes
    </li>
  ));

  return (
    <>
      <div className="file-input">
        <div {...getRootProps({ className: "dropzone" })}>
          <input {...getInputProps()} />
          <p>Drag drop some files here</p>
          <button type="button" onClick={open} disabled={active}>
            Open File Dialog
          </button>
        </div>
        <aside>
          <h4>Files</h4>
          <ul>{files}</ul>
        </aside>
      </div>
    </>
  );
};

App.js

export default function App() {
  return (
    <div className="App">
      <div className="upload-file">
        <h4>Please select file</h4>
        <div>
          <p>Images</p>
          <UploadFile visible />
          <UploadFile visible={false} />
        </div>
        <div>
          <p>Documents</p>
          <UploadFile visible={false} />
          <UploadFile visible={false} />
        </div>
        <br />
        <button type="submit" disabled={true}>
          SEND
        </button>
      </div>
    </div>
  );
}

Solution

  • you can use only one state currentStep as reference at your parent.

    import React, { useCallback, useState } from "react";
    import UploadFile from "./UploadFile";
    import "./styles.css";
    
    export default function App() {
      const [currentStep, setCurrentStep] = useState(1)
      const nextStep = useCallback(() => {setCurrentStep(crr => crr + 1)}, [])
    
      return (
        <div className="App">
          <div className="upload-file">
            <h4>Please select file</h4>
            <div>
              <p>Images</p>
              <UploadFile nextStep={nextStep} currentStep={currentStep} step={1} />
              <UploadFile nextStep={nextStep} currentStep={currentStep} step={2} />
            </div>
            <div>
              <p>Documents</p>
              <UploadFile nextStep={nextStep} currentStep={currentStep} step={3} />
              <UploadFile nextStep={nextStep} currentStep={currentStep} step={4} />
            </div>
            <br />
            <button type="submit" disabled={true}>
              SEND
            </button>
          </div>
        </div>
      );
    }
    

    at Upload File you don't need setState, only compare step with currentStep to check if is enabled. you also need to check step === currentStep once drop is accepted, otherwise if you make multilple changes to the same field, would keep opening other fields.

    import React from "react";
    import { useDropzone } from "react-dropzone";
    
    const UploadFile = ({ nextStep, step, currentStep }) => {
      const onDropAccepted = () => {
            if(step === currentStep) nextStep()
      }
    
      const { getRootProps, getInputProps, open, acceptedFiles } = useDropzone({
        noClick: true,
        noKeyboard: true,
        disabled: step > currentStep,
        onDropAccepted
      });
    
      const files = acceptedFiles.map((file) => (
        <li key={file.path}>
          {file.path} - {file.size} bytes
        </li>
      ));
    
      return (
        <>
          <div className="file-input">
            <div {...getRootProps({ className: "dropzone" })}>
              <input {...getInputProps()} />
              <p>Drag drop some files here</p>
              <button type="button" onClick={open} disabled={step > currentStep}>
                Open File Dialog
              </button>
            </div>
            <aside>
              <h4>Files</h4>
              <ul>{files}</ul>
            </aside>
          </div>
        </>
      );
    };
    
    export default UploadFile;