从子功能组件获取useState并将其附加到对象的父useState数组中

时间:2020-02-12 08:31:47

标签: reactjs typescript

我有一个父组件,它在一个对象数组中保存其所有子组件的信息值。我正在尝试产生一个新的孩子,并以对象数组的形式跟踪那些处于我父母状态的孩子的信息。这是我不知道如何在两个方面进行处理的地方。跟踪状态内的对象并从孩子那里获取内容。

我有一个父级组件:

const Parent: React.FC = () => {
  const [children, setChildren] = React.useState(
    [ 
      {
        id:1, 
        name:'',
        age:0,
      }
    ]
  );
  const getChildName = () => {
     // not sure how to target the new child
  } 

  // Create a new child
  const AddChild = () => {
    let tmpid = children[children.length].id + 1; // not sure if this would work
    setChildren(
      [
        ...children, 
        {
          id:tmpid,
          name:' ',
          age:0,
        }
      ]
    )
  }
  return (
    <button onClick={this.addChild}>Add component</button>
    {
      children.map((child) => (
        <NewChild key={child.id} getChildName={getChildName} getChildAge={getChildAge}/>
      ))
    }
  )
}

然后是一个简单的子组件:

interface IChild {
  name?: string;
  age?: number;
}

type Props = {
  getChildName : void,
  getChildAge : void,
}

const NewChild: React.FC<Props> = (Props) => {
  const [child, setChild] = React.useState<Partial<IChild>>({});

  return (
    <input value={child?.name??''} onChange={e => setChild({...child , child: e.target.value})}/>
    <input value={child?.age??''} onChange={e => setChild({...child , child: parseFloat(e.target.value)})}/>

  )
}

1 个答案:

答案 0 :(得分:1)

看看我如何实现下面的getChildName。它未经测试,但我认为它应该可以工作。还要看一下代码中的注释。如果需要实现getChildAge,则可以执行与getChildName相同的操作,但是返回newChild.age

const Parent: React.FC = () => {
  const [children, setChildren] = React.useState(
    [ 
      {
        id:1, 
        name:'',
        age:0,
      }
    ]
  );
  const getChildName = (id: number) => {
     let newChild = null;

     children.forEach((child) => {
         if (child.id == id) {
             newChild = child;
         }
      }
      return !!newChild ? newChild.name : `No child was found with id ${id}`
  } 

  // Create a new child
  const AddChild = () => {
    /* let tmpid = children[children.length].id + 1; -- this will work. */
    let tmpid = children.length + 1 // This is cleaner, and as long as your id starts on 1,
                                    // this will be the exact same result.
    setChildren(
      [
        ...children, 
        {
          id:tmpid,
          name:' ',
          age:0,
        }
      ]
    )
  }
  return (
    <button onClick={this.addChild}>Add component</button>
    {
      children.map((child) => (
        // You need to add return here.
        return <NewChild key={child.id} getChildName={(child.id) => getChildName(child.id)} getChildAge={getChildAge}/>
      ))
    }
  )
}

就像johnrsharpe所说的那样,不要在两个地方管理相同的状态。您需要给NewChild这样的回调:

<NewChild // Inside Render() method of <Parent />
   key={child.id} 
   getChildName={(child.id) => getChildName(child.id)} 
   getChildAge={getChildAge} 
   callback={updateChildren}
/> 

const updateChildren = (inputChild: IChild) => {  // Method of <Parent />
     const newChildren = children.map((child) => {
         if (child.id = inputChild.id) {
             child.name = inputChild.name;
             child.age = inputChild.age;
         }
         return child;
     }

     setChildren([ ...newChildren ]);
}

在NewChild组件中,而不是使用setChild状态,您可以将对象传递给

之类的函数。
const changeChildProperty = (value: any) => {
    // update property of child

    // Pass in the entire child object, and it will be update in parent state through the callback
    props.callback(child);
}