我期望当props改变时状态重新加载,但是这不起作用,并且在下一个useState
调用中user
变量没有更新,出了什么问题?
function Avatar(props) {
const [user, setUser] = React.useState({...props.user});
return user.avatar ?
(<img src={user.avatar}/>)
: (<p>Loading...</p>);
}
我期望当props改变时状态重新加载,但是这不起作用,并且在下一个useState
调用中user
变量没有更新,出了什么问题?
function Avatar(props) {
const [user, setUser] = React.useState({...props.user});
return user.avatar ?
(<img src={user.avatar}/>)
: (<p>Loading...</p>);
}
useState接收到的参数是初始状态,就像在类组件的构造函数中设置状态一样,并且不用于重新渲染时更新状态。
如果您想在属性更改时更新状态,请使用useEffect钩子。
function Avatar(props) {
const [user, setUser] = React.useState({...props.user});
React.useEffect(() => {
setUser(props.user);
}, [props.user])
return user.avatar ?
(<img src={user.avatar}/>)
: (<p>Loading...</p>);
}
React.useEffect
在每次设置初始状态。 - CMCDragonkai// App.jsx
function App() {
// ...logic here
return <Avatar initialUser={user} key={user.id} />
}
// Avatar.jsx
function Avatar({ initialUser }) {
// I suppose you need this component to manage it's own state
// otherwise you can get rid of this useState altogether.
const [user, setUser] = React.useState(initialUser);
return user.avatar ? (
<img src={user.avatar} />
) : (
<p>Loading...</p>
);
}
key
属性看作是useEffect的依赖数组,但是由于组件渲染触发的意外useEffect
调用不会导致意外的状态改变。useEffect
可能成为一个隐患的更多信息,请参考以下链接:
也许你并不需要Effect
函数式组件中,我们使用useState
来设置变量的初始值。如果我们通过props传递初始值,它将始终设置相同的初始值,直到您使用useEffect
钩子。
例如,在您的情况下,这将完成您的工作。
React.useEffect(() => {
setUser(props.user);
}, [props.user])
useEffect传递的函数将在呈现提交到屏幕后运行。
默认情况下,effect会在每次完成呈现后运行,但是您可以选择仅在某些值更改时触发它们。
React.useEffect(FunctionYouWantToRunAfterEveryRender)
如果您只将一个参数传递给 useEffect,它将在每次渲染后运行此方法。 您可以通过向 useEffect 传递第二个参数来决定何时触发这个 FunctionYouWantToRunAfterEveryRender
React.useEffect(FunctionYouWantToRunAfterEveryRender, [props.user])
请注意,现在我正在传递 [props.user]。使用 useEffect
时,只有在 props.user
发生变化时才会触发 FunctionYouWantToRunAfterEveryRender
函数。
希望这有助于您的理解。如果需要改进,请告诉我。谢谢。
https://gist.github.com/mahmut-gundogdu/193ad830be31807ee4e232a05aeec1d8
import {useEffect, useState} from 'react';
export function useStateWithDep(defaultValue: any) {
const [value, setValue] = useState(defaultValue);
useEffect(() => {
setValue(defaultValue);
}, [defaultValue]);
return [value, setValue];
}
#示例
const [user, setUser] = useStateWithDep(props.user);
function useStateWithDep<T>(defaultValue: T)
,return [value, setValue] as const
。 - tokland我创建了像这样的自定义钩子:
const usePrevious = value => {
const ref = React.useRef();
React.useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
const usePropState = datas => {
const [dataset, setDataset] = useState(datas);
const prevDatas = usePrevious(datas);
const handleChangeDataset = data => setDataset(data);
React.useEffect(() => {
if (!deepEqual(datas, prevDatas)) // deepEqual is my function to compare object/array using deep-equal
setDataset(datas);
}, [datas, prevDatas]);
return [
dataset,
handleChangeDataset
]
}
使用方法:
const [state, setState] = usePropState(props.datas);
React.useState()
中传递的参数仅为该状态的初始值。React不会将其视为更改状态,而只是设置其默认值。您需要最初设置默认状态,然后有条件地调用setUser(newValue)
,这将被识别为新状态并重新呈现组件。
props.user
没有任何意义。 - tokland