【问题标题】:React: Passing local state to parent componentReact:将本地状态传递给父组件
【发布时间】:2021-09-09 09:08:20
【问题描述】:

我正在尝试在 React 中创建一个可重用的“模态”组件。 Modal 组件将有一些输入字段和一个提交按钮,当用户单击 Modal 中的提交按钮时。模式应该关闭,并且用户在输入字段中输入的数据应该通过父组件中声明的回调函数传递给父组件。代码工作正常,但我认为(不确定)这不是正确的解决方案,因为我必须在 Modal(子)组件和使用 Modal 组件的父组件中创建“反应状态”。正如您所看到的(沙箱代码),状态在两个组件中都是重复的,我想知道如何将状态只保留在一个地方。我的理解是我肯定需要在 Modal 组件中为输入字段创建一个状态以跟踪更改,但我不确定如何在不创建相同状态的情况下在父组件中使用该数据

这是我创建的一个沙盒,用于展示我到目前为止所做的事情:

https://codesandbox.io/s/jovial-matsumoto-1zl9b?file=/src/Modal.js

【问题讨论】:

    标签: reactjs react-props react-component react-state


    【解决方案1】:

    您可以在 App 组件中定义这些状态:

    const [showModal, setShowModal] = useState(false);
    const [user, setUser] = useReducer(reducer, {
        firstName: "",
        lastName: ""
    });
    
    const toggleModal = () => {
        setShowModal(!showModal);
    };
    

    在渲染 Modal 组件时将它们传递给props

    <div className="App">
        <h2>First Name is : {firstName}</h2>
        <h2>Last Name is : {lastName}</h2>
        <button className="toggle-button" onClick={toggleModal}>
            Show Modal
        </button>
        <Modal
            show={showModal}
            hide={() => toggleModal(false)}
            user={user}
            updateUser={setUser}
        />
    </div>
    

    然后,在您的 Modal 组件中,为 firstNamelastName 定义状态:

    const Modal = (props) => {
        const [firstName, setFirstName] = useState(props.user.firstName);
        const [lastName, setLastName] = useState(props.user.lastName);
    
        const onFirstNameChange = ({ target }) => {
            setFirstName(target.value);
        };
    
        const onLastNameChange = ({ target }) => {
            setLastName(target.value);
        };
        
        // ...
    }
    

    现在您可以从 Modal 组件中提交类似的更改:

    const onFormSubmit = (e) => {
        props.updateUser({
            firstName,
            lastName
        });
        props.hide();
    };
    

    【讨论】:

    • 感谢您的回复,想知道​​如果我在“模态”组件中有 10-15 个输入字段,那么看起来我需要通过道具传递相同数量的字段。这是一个正确的方法吗?
    • 是的,这就是为什么在我的代码和框中我使用了不同的东西:我使用了 useReducer 钩子,所以它更好,因为我们不需要为模式的每个输入字段传递一个新的道具。跨度>
    • @learnbydoing 我对我的帖子进行了编辑,以向您展示我所做的更改。
    • 我认为您错过了我原始帖子中的一件事,我打算在单击 Modal 上的提交按钮时提交模态数据,该按钮需要在父组件上可见,但您的实现正在更新父组件prop 当我们在输入字段中输入文本时,它应该传递给父组件,只有我们通过提交按钮提交
    • 是的,我错过了。所以我更新了我的帖子以及sandbox。现在是你所期望的吗?
    【解决方案2】:

    为了不重复状态,我会将模态中的输入包含在 form 元素中,并将输入转换为不受控制的输入。提交表单时,获取表单字段值并传入formData 回调并重置表单。将按钮显式声明为type="submit"

    const Modal = (props) => {
      const onFormSubmit = (e) => {
        e.preventDefault();
    
        const firstName = e.target.firstName.value;
        const lastName = e.target.lastName.value;
    
        props.formData({ firstName, lastName });
        e.target.reset();
      };
    
      if (!props.show) {
        return null;
      } else {
        return (
          <div className="modal" id="modal">
            <form onSubmit={onFormSubmit}>
              <input type="text" name="firstName" />
              <input type="text" name="lastName" />
              <button className="toggle-button" type="submit">
                Submit
              </button>
            </form>
          </div>
        );
      }
    };
    

    看来您的问题的症结在于您的父组件和模态之间的代码重复。我在这里真正建议的是将模态与任何特定用例分离,并允许任何消费父组件传递关闭处理程序和子组件。

    这将状态保留在父级中,从而控制。

    模态组件示例:

    const Modal = ({ onClose, show, children }) =>
      show ? (
        <div className="modal" id="modal">
          <button type="button" onClick={onClose}>
            X
          </button>
          {children}
        </div>
      ) : null;
    

    家长:

    function App() {
      const [isShowModal, setIsShowModal] = useState(false);
      const [firstName, setFirstName] = useState();
      const [lastName, setLastName] = useState();
    
      const showModal = (e) => {
        setIsShowModal((show) => !show);
      };
    
      const closeModal = () => setIsShowModal(false);
    
      const onFormSubmit = (e) => {
        e.preventDefault();
    
        const firstName = e.target.firstName.value;
        const lastName = e.target.lastName.value;
    
        setFirstName(firstName);
        setLastName(lastName);
    
        e.target.reset();
        closeModal();
      };
    
      return (
        <div className="App">
          <h2>First Name is : {firstName}</h2>
          <h2>Last Name is : {lastName}</h2>
          <button className="toggle-button" onClick={showModal}>
            Show Modal
          </button>
          <Modal show={isShowModal} onClose={closeModal}>
            <form onSubmit={onFormSubmit}>
              <input type="text" name="firstName" />
              <input type="text" name="lastName" />
              <button className="toggle-button" type="submit">
                Submit
              </button>
            </form>
          </Modal>
        </div>
      );
    }
    

    这完全取决于您希望如何管理父内容和模态内容之间的交互。我已经展示了使用表单和表单操作,因此在用户提交表单之前您的状态不会更新。您可以使用表单实用程序(redux-form、formix 等)或滚动您自己的管理。生活是一座花园,挖掘吧。

    【讨论】:

    • 感谢您的回复,我喜欢这个想法,但只是要求我接受教育。那么当我们想要将数据从孩子传递给父母时,这是一种推荐的方式吗?另外,为什么我们需要将按钮类型设置为“提交”?
    • @learnbydoing 如果您不想“复制”状态,建议您这样做,但老实说,使用受控输入也没有错。我真正想做的是将模态容器与其内容分离。换句话说,让父组件(作为子组件)传递模态内容,并在模态渲染时使用父组件中的单个状态和处理程序。如果您对此感兴趣,我可以添加一个演示。好吧,如果你不指定类型,按钮的默认值为type="submit",但显式有助于其他开发人员。
    • 这对我来说真的很有帮助,所以看起来当我们有父子关系并且需要将数据从子组件传递给父组件时,我们应该将子内容与其内容分离,而是使用{children} 哪里 children 是从它的父级传递的实际内容?或者您能否解释一下何时使用此策略而不是我在原始帖子中使用的策略?
    猜你喜欢
    • 2022-07-15
    • 2019-03-08
    • 2020-07-04
    • 2019-01-20
    • 2022-01-18
    • 1970-01-01
    • 2019-01-12
    • 1970-01-01
    • 2019-02-17
    相关资源
    最近更新 更多