我正在使用 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} />
</>
);
第一次
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}) {....}
在正确加载对象之前,不应渲染 ChildComponent。因此,您可以简单地检查该对象是否仍然为空或已被填充,并使您的 ChildComponent 依赖于该信息,例如如下所示:
return (
<>
{myObject.id !== '' && <ChildComponent obj={myObject} setObj={setMyObject} />}
</>
);
从技术上讲,您还可以摆脱 ChildComponent 中的附加状态,并只传递对象的 Set-Function (参见上文)。然而,如果发生任何变化,ParentComponent 将被重新渲染。如果您有一个非常依赖性能的应用程序,这可能不是最好的方法。
除此之外,如果您使用对象更新状态,则应该始终创建一个新对象,以避免副作用。像这样设置:
setMyObject({...x});