Reactjs React从父组件收集有关某个事件的子组件数据

Reactjs React从父组件收集有关某个事件的子组件数据,reactjs,Reactjs,在react最佳实践中,数据流从父级流向子级,事件将从子级传递到父级 在这个UI中,我们有一个父组件,它包含两个子组件和表单。现在,当用户单击父组件中的submit按钮时,我们必须从子组件收集数据 可能的解决方案(不良解决方案|反模式): 从子级传递ref并从父级触发子方法以收集数据(从父级访问子方法不是一个好主意) onFormData(数据){ //这里收集孩子的数据 } onSubmit(){ //在子对象中触发数据的方法 aRef.collectData() } 提交 将道具绑定到

在react最佳实践中,数据流从父级流向子级,事件将从子级传递到父级

在这个UI中,我们有一个父组件,它包含两个子组件和表单。现在,当用户单击父组件中的submit按钮时,我们必须从子组件收集数据

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

  • 从子级传递ref并从父级触发子方法以收集数据(从父级访问子方法不是一个好主意)
  • 
    onFormData(数据){
    //这里收集孩子的数据
    }
    onSubmit(){
    //在子对象中触发数据的方法
    aRef.collectData()
    }
    提交
    
  • 将道具绑定到子道具,在提交时单击“使用虚拟值更改道具值”。观察使用中的相同道具效果挂钩(非常糟糕的解决方案)
  • 
    onFormData(数据){
    //这里收集孩子的数据
    }
    onSubmit(){
    //更新randomValue,该值将在从子级调用onData方法的useEffect中观察到
    randomValue=Math.random();
    }
    提交
    
    有没有其他处理这些场景的最佳方法?如何避免此UI出现反模式?

    我通常做的是将状态提升到父级。这意味着我不会打破自然的反应流程,也就是从父母向孩子传递道具。按照您的示例,我会将所有逻辑放在父级中(提交函数、表单状态等)

    Const Parent=()=>{
    const[formData,setFormData]=useState({})
    const onSubmitForm=()=>{
    //将表单数据发送到某处
    }
    返回(
    onSubmitForm()}>my按钮
    )
    }
    
    现在,每当ChildrenForm中的输入发生更改时,我都会在ChildrenForm中使用
    onChange
    函数来更新
    formData
    。因此,我的所有状态都将在父级,我不需要担心必须放弃一切,从子级到父级(如您所述的反模式)

    我通常做的是将状态提升到父级。这意味着我不会打破自然的反应流程,也就是从父母向孩子传递道具。按照您的示例,我会将所有逻辑放在父级中(提交函数、表单状态等)

    Const Parent=()=>{
    const[formData,setFormData]=useState({})
    const onSubmitForm=()=>{
    //将表单数据发送到某处
    }
    返回(
    onSubmitForm()}>my按钮
    )
    }
    
    现在,每当ChildrenForm中的输入发生更改时,我都会在ChildrenForm中使用
    onChange
    函数来更新
    formData
    。因此,我的所有状态都将在父级,我不需要担心从子级到父级(如您所述的反模式)

    有第三种选择(这是标准方式):您不收集数据,而是将您的
    formData
    setFormData
    作为道具传递给每个
    子级。使用方法

    每个
    Child
    formData
    填充其输入值,并使用
    setFormData
    更新位于
    Parent
    上的
    formData
    。最后,在提交时,您只需为请求调用设置
    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> 
        </>
      );
    }
    
    const ChildA=({formData,setFormData})=>{
    常量{name,age}=formData
    const onChange=({target:{name,value}}})=>{//对“name”和“value”进行解构
    setFormData(formData=>({…formData,[名称]:值}))//扩展formData,使用'name'键更新字段
    }
    返回(
    名称
    年龄
    );
    }
    const ChildB=({formData,setFormData})=>{
    const{email,acceptTerms}=formData
    const onChange=({target:{name,value}})=>{
    setFormData(formData=>({…formData,[名称]:值}))
    }
    const onClick=({target:{name,checked}})=>{
    setFormData(formData=>({…formData,[名称]:选中}))
    }
    返回(
    电子邮件
    接受条件
    );
    }
    常量父项=()=>{
    //使用了一个formData。如果愿意,可以细分为更多
    const[formData,setFormData]=useState({name:'',年龄:null,acceptTerms:false,电子邮件:undefined})
    const onSubmit=(e)=>{
    e、 预防默认值()
    //在这里,您实现了提交表单的逻辑
    console.log(formData)
    }
    返回(
    提交
    );
    }
    
    还有第三种选择(这是标准方法):您不收集数据,而是将
    formData
    setFormData
    作为道具传递给每个
    子项。使用方法

    每个
    Child
    formData
    填充其输入值,并使用
    setFormData
    更新位于
    Parent
    上的
    formData
    。最后,在提交时,您只需为请求调用设置
    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> 
        </>
      );
    }
    
    const ChildA=({formData,setFormData})=>{
    常量{name,age}=formData
    const onChange=({target:{name,value}}})=>{//对“name”和“value”进行解构
    setFormData(formData=>({…formData,[名称]:值}))//扩展formData,使用'name'键更新字段
    }
    返回(
    名称
    年龄
    );
    }
    const ChildB=({formData,setFormData})=>{
    const{email,acceptTerms}=formData
    const onChange=({target:{name,value}})=>{
    setFormData(formData=>({…formData,[名称]:值}))
    }
    const onClick=({target:{name,checked}})=>{
    setFormData(formData=>({…formData,[名称]:选中}))
    }
    返回(
    电子邮件
    接受条件
    );
    }
    常量父项=()=>{
    //使用了一个formData。如果愿意,可以细分为更多
    const[formData,setFormData]=useState({name:'',年龄:null,acceptTerms:false,电子邮件:undefined})
    const onSubmit=(e)=>{
    e、 上
    
    Const Parent = () => {
      const [formData, setFormData] = useState({})
    
      const onSubmitForm = () => {
          // send formData to somewhere
      }
    
      return (
          <ChildrenForm onChange={setFormData} formData={formData} />
          <button onSubmit={() => onSubmitForm()}>my button</button>
      )
    }
    
    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> 
        </>
      );
    }
    
    // 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]);