【问题标题】:React change state next component反应改变状态下一个组件
【发布时间】:2020-12-04 12:48:01
【问题描述】:

我必须为输入类型文件创建上传文件唯一组件,因为我使用 react-dropzone 库进行拖放并在页面中使用此组件 4 次。最初,除了第一个组件,其他组件必须禁用,但加载文件后,下一个组件必须将状态更改为 disable = {true}。如何使用 useState 正确实现逻辑?

sandbox

上传文件.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>
  );
}

【问题讨论】:

    标签: reactjs react-dropzone


    【解决方案1】:

    您只能使用一个州 currentStep 作为您父母的参考。

    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>
      );
    }
    

    在 Upload File 中不需要 setState,只需将 step 与 currentStep 进行比较以检查是否已启用。您还需要在接受 drop 后检查step === currentStep,否则如果您对同一字段进行多次更改,将继续打开其他字段。

    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;
    

    【讨论】:

      【解决方案2】:

      可以使用react context来创建各个组件之间的关系,在第一个文件drop之后,可以进入upload组件的下一个索引

      上传文件.js

      import React, { useEffect, useState, useContext } from "react";
      import { useDropzone } from "react-dropzone";
      import { DragContext } from "./App";
      
      const UploadFile = ({ index = 0 }) => {
        const { currentIndex, setCurrentIndex } = useContext(DragContext); // use context
        const [active, setActive] = useState(false);
      
        useEffect(() => {
          if (index !== currentIndex) { // compare to active 
            setActive(true);
          } else {
            setActive(false);
          }
        }, [currentIndex, index]);
      
        console.log(active);
      
        const { getRootProps, getInputProps, open, acceptedFiles } = useDropzone({
          noClick: true,
          noKeyboard: true,
          disabled: active,
          onDropAccepted: () => {
            setCurrentIndex(currentIndex + 1);
          }
        });
      
        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>
          </>
        );
      };
      
      export default UploadFile;
      
      

      App.js

      import React, { createContext, useState } from "react";
      import UploadFile from "./UploadFile";
      import "./styles.css";
      
      export const DragContext = createContext({});
      
      export default function App() { 
        const [currentIndex, setCurrentIndex] = useState(0); // compare with index
        return (
          <div className="App">
            <DragContext.Provider value={{ currentIndex, setCurrentIndex }}>
              <div className="upload-file">
                <h4>Please select file</h4>
                <div>
                  <p>Images</p>
                  <UploadFile index={0} />
                  <UploadFile index={1} />
                </div>
                <div>
                  <p>Documents</p>
                  <UploadFile index={2} />
                  <UploadFile index={3} />
                </div>
                <br />
                <button type="submit" disabled={true}>
                  SEND
                </button>
              </div>
            </DragContext.Provider>
          </div>
        );
      }
      
      

      【讨论】:

      • 感谢代码工作,但如何保持启用以前的输入?因为如果用户想要下载另一个文件和所有上传文件启用按钮?
      • 你可以比较 currentIndex 和 index , if currentIndex > index and setActive(false)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-25
      • 1970-01-01
      • 2022-06-21
      • 2020-10-12
      • 2016-11-06
      • 2022-11-19
      • 2018-09-01
      相关资源
      最近更新 更多