React State 未从 prop 初始化

问题描述 投票:0回答:2

我正在使用 React 和 TypeScript。我是 React 新手,我不确定如何确保子组件根据传递给它的 prop 正确设置状态。

我将一个对象作为 prop 从父组件传递到子组件中。父组件有一个带有键和空值的对象。下面是一个例子 -

emptyObject = {
    id: '',
    name: '',
    timestamp: ''
}

异步函数

foo
查询数据库并根据组件的 prop 填充值,然后返回更新后的对象的 Promise。然后,更新后的对象应传递给子组件,其中值存储为状态。

function ParentComponent({propName}) {
    const [myObject, setMyObject] = useState(emptyObject);

    useEffect( () => {
        foo(emptyObject).then((x) => {
            setMyObject(x);
        });
    }, [propName]);

    return (
        <>
            <ChildComponent obj = {myObject} />
        </>
    );
}


function ChildComponent({obj}) {
    const {id, name, timestamp} = obj;
    console.log("id: " + id + ". name: " + name) // this gives the correct values
    
    const [myId, setMyId] = useState(id)
    const [myName, setMyName] = useState(name);
    console.log("id: " + myId + ". name: " + myName) // this gives "id: undefined. name: undefined"


    return (
        <displays a form that is pre-populated with the id and name values>
    )
}

我面临的问题是,解构对象给了我正确的值,但 State 中的值是未定义的。我怀疑这是因为在 React 中设置 State 是异步的,但我不知道如何解决这个问题。

我尝试的第一件事是在子组件中添加一个钩子,但出现了同样的问题。

function ChildComponent({obj}) {
    const {id, name, timestamp} = obj;
    const [myId, setMyId] = useState(id)
    const [myName, setMyName] = useState(name);
    
    useEffect( () => {
        setMyId(id);
        setMyName(name);
    }, [obj]);

我还尝试在父级中实现两个

useEffects
,并修改原始
useEffect
中的逻辑,以确保值已更新,但仍然会发生相同的结果。

const [myObject, setMyObject] = useState(emptyObject);
const [updatedObject, setUpdatedObject] = useState(emptyObject);

    useEffect( () => {
       foo(emptyObject).then((x) => {
           setUpdatedObject(x);
       });
    }, [propName]);

    useEffect( () => {
        setMyObject(updatedObject);
    }, [updatedObject]);

    return (
        <>
            <ChildComponent obj = {myObject} />
        </>
    );
reactjs typescript setstate
2个回答
1
投票

第一次

child
渲染时,道具传递给它的值等于您设置的初始值(这就是您未定义的原因),直到
foo
函数设置道具。 useState 钩子仅首先初始化,当初始化值更新时,状态不会更新。

您可以通过侦听

child
中的 prop 更新来解决此问题,如下所示。

function ChildComponent({obj}) {
    const [myId, setMyId] = useState('')
    const [myName, setMyName] = useState('');
    
    useEffect(()=>{
      setMyName(obj.name) 
      setMyId(obj.id) 
    },[obj]);    

    return (
        <displays a form that is pre-populated with the id and name values>
    )
}

我的建议是使用您传递给

child
的道具,因为它已经是
parent
中的状态,并且 make rerender 中的任何更改都会发送给您
child

function ChildComponent({ obj,  }) {
  const myId = obj.id; // or use it directly `obj.id`
  const myName = obj.name; // or use it directly `obj.name`
    
     .....
}

如果您需要从

child
更新 prop,请将 setter 函数作为 prop 传递
setMyObject

function ChildComponent({obj, setMyObject}) {....}

1
投票

在正确加载对象之前,不应渲染 ChildComponent。因此,您可以简单地检查该对象是否仍然为空或已被填充,并使您的 ChildComponent 依赖于该信息,例如如下所示:

return (
    <>
        {myObject.id !== '' && <ChildComponent obj={myObject} setObj={setMyObject} />}
    </>
);

从技术上讲,您还可以摆脱 ChildComponent 中的附加状态,并只传递对象的 Set-Function (参见上文)。然而,如果发生任何变化,ParentComponent 将被重新渲染。如果您有一个非常依赖性能的应用程序,这可能不是最好的方法。

除此之外,如果您使用对象更新状态,则应该始终创建一个新对象,以避免副作用。像这样设置:

setMyObject({...x});
© www.soinside.com 2019 - 2024. All rights reserved.