【问题标题】:React collect child component data on some event from the parent componentReact 从父组件收集某些事件的子组件数据
【发布时间】:2021-04-12 20:58:48
【问题描述】:

在反应最佳实践中是从父级到子级的数据流,事件将从子级传递到父级。

在这个 UI 中,我们有一个父组件,其中包含 2 个带有表单的子组件。当用户点击父组件中的提交按钮时,我们现在必须从子组件收集数据。

可能的解决方案(坏解决方案 | 反模式):

  1. 从子节点传递 ref 并从父节点触发子方法以收集数据(从父节点访问子方法不是一个好主意)
 <Parent>
    onFormData(data) {
     //here collect data from child
    }

    onSubmit() {
      //Trigger a method onData in child
      aRef.collectData()
    }

    <child-A ref={aRef} onData={onFormData}></Child-A>
    <Child-B ref={bRef} onData={onFormData}></Child-B>
    
    <button onClick={onSubmit}>Submit</Submit> 
</Parent>
  1. 将道具绑定到孩子,在提交点击时将道具的值更改为虚拟值。在 useEffect 挂钩中观察相同的道具(非常糟糕的解决方案)
 <Parent>
    onFormData(data) {
     //here collect data from child
    }

    onSubmit() {
      //update randomValue, which will be observed in useEffect that calls onData method from child
      randomValue = Math.random();
    }

    <child-A triggerSubmit={randomValue} onData={onFormData}></Child-A>
    <Child-B triggerSubmit={randomValue} onData={onFormData}></Child-B>
    
    <button onClick={onSubmit}>Submit</Submit> 
</Parent>

还有其他处理这些情况的最佳方法吗?如何避免此 UI 的反模式?

【问题讨论】:

  • 为了更好地回答这个问题,您能否解释一下为什么需要两种形式而不是一种形式?
  • 这里甚至可能只是一种形式..这只是一个解释问题的示例..这里的问题是当提交按钮在父级时如何通知子级触发事件.. .
  • 你有没有找到解决这个问题的好方法?

标签: reactjs


【解决方案1】:

我通常做的是向父母“提升状态”。这意味着我不会破坏自然的 React 流程,即将 props 从父级传递给子级。按照您的示例,我会将所有逻辑放在父级中(提交函数、表单状态等)

Const Parent = () => {
  const [formData, setFormData] = useState({})

  const onSubmitForm = () => {
      // send formData to somewhere
  }

  return (
      <ChildrenForm onChange={setFormData} formData={formData} />
      <button onSubmit={() => onSubmitForm()}>my button</button>
  )
}

现在我将使用 Children 中的 onChange 函数来更新 formData ,每当 ChildrenForm 中的输入发生变化时。所以我所有的状态都将在父级中,我不必担心必须将所有内容从子级传递到父级(您提到的反模式)

【讨论】:

    【解决方案2】:

    还有第三个选项(这是标准方式):您不收集数据,您将 formDatasetFormData 作为道具传递给每个 Child。使用lift state 方法。

    每个Child 都用formData 填充其输入值,并使用setFormData 更新formData 上的Parent。最后,在提交时,您只需将formData设置为您的请求调用。

    下面是一个例子:

    const ChildA = ({ formData, setFormData }) => {
      const { name, age } = formData
      const onChange = ({ target: { name, value } }) => { // destructuring 'name' and 'value'
        setFormData(formData => ({ ...formData, [name]: value })) // spread formData, update field with 'name' key
      }
      return (
        <>
          <label>Name<input type="text" onChange={onChange} name="name" value={name} /></label>
         <label>Age<input type="number" onChange={onChange} name="age" value={age} /></label>
        </>
      );
    }
    
    const ChildB = ({ formData, setFormData }) => {
      const { email, acceptTerms } = formData
      const onChange = ({ target: { name, value } }) => {
        setFormData(formData => ({ ...formData, [name]: value }))
      }
    
      const onClick = ({ target: { name, checked } }) => {
        setFormData(formData => ({ ...formData, [name]: checked }))
      }
    
      return (
        <>
          <label>email<input type="email" onChange={onChange} name="email" value={email} /></label>
          <label>Accept Terms<input type="checkbox" onChange={onClick} name="acceptTerms" checked={acceptTerms} /></label>
        </>
      );
    }
    
    
    const Parent = () => {
      // used one formData. you could break down into more if you prefer
      const [formData, setFormData] = useState({ name: '', age: null, acceptTerms: false, email: undefined }) 
    
      const onSubmit = (e) => {
        e.preventDefault()
        // here you implement logic to submit form
        console.log(formData)
      }
    
      return (
        <>
          <ChildA formData={formData} setFormData={setFormData} />
          <ChildB formData={formData} setFormData={setFormData} />
          <button type="submit" onClick={onSubmit}>Submit</button> 
        </>
      );
    }
    

    【讨论】:

    • 但是如果我们使用像 hookform 或 formik 这样的第三方库呢?在这种情况下,我们将只收集一次数据..
    • @ksh 无论您是否使用第 3 方表单库,您都不会只收集一次数据。给定每个 lib 实现,它都有它的 tweeks,但表单值总是更新。并且您应该在提交时提供它们
    • 让我们忘记这个例子......请帮助我理解是否不可能触发事件从父母到孩子?还是只是反应不好的做法
    【解决方案3】:

    方法 2) 随机并不是真的那么糟糕!只有这个保留了不涉及 DOM/withRef 往返的封装。建议的 Up State 方式会导致硬编码依赖并破坏可重用性的整体理念。我唯一要提到的是:上面键入的代码将不起作用 - 因为通常的变量不会触发。这样做的正确方法:

    // Parent component
    
    let [randomValue, setRandomValue] = React.useState(Math.random());
    const onSubmit = () => { 
      setRandomValue(Math.random());
      console.log("click");
    }
    const onFormData  = data => {
      console.log(`${data}`);
    }
    ...
    <Child triggerSubmit={randomValue} onData={onFormData}/>
    
    // Child component
    
    useEffect(() => {
      console.log("child id here");
      prop.onData(`Hey Ho! Lets go!`)
    }, [prop.triggerSubmit]);
    

    至少这对我有用!

    【讨论】:

      猜你喜欢
      • 2016-01-19
      • 1970-01-01
      • 2020-09-28
      • 2022-06-30
      • 2019-03-11
      • 2020-03-15
      • 2019-09-07
      相关资源
      最近更新 更多