状态从父级到子级的更改未反映到React Hook中的TextField

时间:2019-12-14 08:32:30

标签: reactjs react-hooks

我将组件(C)作为道具传递给父组件(A)内的子组件(B)。 A的状态也传递给C并映射到C的状态。但是当我相应地更新A状态和B状态时,C状态不会更新。

我的代码如下:(省略了导入语句)

const Parent = (props) => {
    .............(other state)
    const [info, setInfo] = React.useState(props.info);

    const handleDataChanged = (d) => { setInfo(d); }

    return (
        <div>
            ........(other stuffs)
            <MyModal
                ..........(other props)
                body={ <MyComp data={ info } updateData={ handleDataChanged } /> }
            />
        </div>
    );
}


const MyModal = (props) => {
    ..........(other state)
    const [content, setContent] = React.useState(props.body);

    React.useEffect(() => { setContent(props.body); }, [props]);

    return (
        <Modal ...>
            <div>{ content }</div>
        </Modal>
    );
}


const MyComp = (props) => {
    const [data, setData] = React.useState(props.data);

    React.useEffect(() => { setData(props.data); }, [props]);

    return (
        data && <TextField value={ data.name }
                           onChange={ e => {
                                      let d = data;
                                      d.name = e.target.value;
                                      props.updateData(d); }} />
    );
}

当我在TextField中键入内容时,我看到Parent的{​​{1}}发生了变化。 info的{​​{1}}未触发。并且useEffect中的MyModal未更新。

更新:在进一步检查了上面的代码和下面的解决方案之后,问题仍然存在,但是我发现data中的MyComp确实从data进行了更改,但是TextField确实存在不能反映出来。

请有人告诉我如何从MyComp更新Parent并将其反映到data。非常感谢!

2 个答案:

答案 0 :(得分:1)

实际上,您似乎正在尝试重新创建子级api https://reactjs.org/docs/react-api.html#reactchildren

如果使用props.children而不是上下传递props.children来组成组件,则容易得多。

const MyModal = (props) => {
    ...(other state)
    return (
        <Modal>
            <div>{ props.children }</div>
        </Modal>
    );
}

然后,您可以直接在父级中处理功能,而不必将道具映射到状态(强烈建议)...

const Parent = (props) => {
    ...(other state)
    const [info, setInfo] = React.useState(props.info);

    const handleDataChanged = d => setInfo(d);

    return (
        <div>
            ...(other stuffs)
            <MyModal {...props}>
             <MyComp data={ info } updateData={ handleDataChanged } /> 
           </MyModal>
        </div>
    );
}

此方法的优点是开销少得多。无需将状态A传递给C并映射到C的状态,您可以执行状态A(父组件)中的所有操作。无需映射,您就可以掌握状态的真实来源,并且更易于思考和建立。

或者,如果您想坚持当前的方法,只需在React.useEffect(() => { setContent(props.body); }, [props]);中删除MyModal并像这样直接映射道具

<Modal>
  <div>{ props.body }</div>
</Modal>

答案 1 :(得分:0)

我的代码的真正问题是:React Hook不知道状态对象中的特定属性或元素是否已更改。它只知道整个对象是否已更改。

例如:如果您的状态中包含3个元素的数组或Json对象。如果数组中的一个元素发生了变化,或者Json对象中的一个属性发生了变化,React Hook会确定它们不变。

因此,要实际广播更改,必须将对象深度克隆为副本,然后将该副本设置回您的状态。为此,我使用lodash进行了深层克隆。

参考:https://dev.to/karthick3018/common-mistake-done-while-using-react-hooks-1foj

因此代码应为:

在MyComp中:

onChange={e => { let d = _.cloneDeep(data); d.name = e.target.value; props.handleChange(d) }}

在父母中:

const handleChange = (data) => {
    let d = _.cloneDeep(data);
    setInfo(d);
}

然后按常规将handleChange作为委托传递给MyComp。