Reactjs componentDidUpdate到挂钩的转换
我想把这个生命周期改写成一个钩子:Reactjs componentDidUpdate到挂钩的转换,reactjs,react-redux,material-ui,react-hooks,Reactjs,React Redux,Material Ui,React Hooks,我想把这个生命周期改写成一个钩子: componentDidUpdate = prevProps => { const { notifications, popNotification } = this.props; if (prevProps.notifications.length >= notifications.length) return; const [notification] = notifications; popNotifica
componentDidUpdate = prevProps => {
const { notifications, popNotification } = this.props;
if (prevProps.notifications.length >= notifications.length) return;
const [notification] = notifications;
popNotification(notification.id);
this.setState({
open: true,
message: notification.text,
variant: notification.variant,
});
};
我知道我必须使用useEffect挂钩,但直到现在它才开始工作。这就是我到目前为止的想法:
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
const dispatch = useDispatch();
const popMessage = useCallback(id =>
dispatch(NotificationActions.popNotification(id))
);
const notifications = useSelector(state => state.notifications);
const previousValue = usePrevious(notifications.length);
useEffect(() => {
if (previousValue >= notifications.length) return;
// Extract notification from list of notifications
const [notification] = notifications;
popMessage(notification.id);
// Open snackbar
setSnackbar({
open: true,
message: notification.text,
variant: notification.variant,
});
});
此尝试与旧方法不同,它的调用次数比旧方法多,并且还会抛出
TypeError:notification is undefined
。此外,如果在提取通知之前添加一个if(notifications.length>0)
,它仍然不起作用。您可以使用第二个参数(变量数组)限制useEffect何时触发
在第一次加载或变量更改值时,将触发使用效果,如果不指定任何内容作为第二个参数,则每次重新渲染都将触发使用效果 若要用
useffect
钩子替换componentdiddupdate
,请将第二个参数和一组变量传递给钩子,这些变量必须从该渲染更改为下一个渲染才能运行钩子
useEffect(() => {
// your code
},[props.notifications])
两个问题一个问题我可以看到你的钩子代码:
usePrevious
将永远不会更新超过第一个值集
当在useffect
中未设置依赖项时,它将运行一次,并且只运行一次。在您的情况下,由于要跟踪上一个值集,您需要使其成为useffect
的依赖项,即useffect(()=>…,[value])
,这将强制回调重新运行并更新ref
原来我误解了,当函数组件重新渲染时,它会重新运行挂钩的效果,您可以忽略第1点useffect
中的主更新代码与第1点类似,只运行一次
同样,当通知计数发生更改时,代码将重新运行,因此需要设置为依赖项useffect(()=>…,[notifications.length])
通知未定义
,这表明您的通知
状态不是有效数组或数组为空,请检查useSelector(state=>state.notifications)的结果
根据您的代码,我希望它看起来是这样的
const dispatch = useDispatch();
const popMessage = useCallback(id =>
dispatch(NotificationActions.popNotification(id))
, []);
const notifications = useSelector(state => state.notifications);
const previousValue = usePrevious(notifications.length);
useEffect(() => {
if (!notifications.length || previousValue >= notifications.length) return;
// Extract notification from list of notifications
const [notification] = notifications;
if (!notification) return;
popMessage(notification.id);
// Open snackbar
setSnackbar({
open: true,
message: notification.text,
variant: notification.variant,
});
}, [notifications]);
您不需要在usePrevious的useEffect中添加
[value]
?类似这样:useffect(()=>{…},[value])
。同样在另一个useEffect中,我认为您应该在useEffect中添加[通知]
。至少这个不应该比旧的多。看看这里的usePrevious:对不起,我错了。只需使用props.notifications
。谢谢您更新答案并帮助我。我用了不同的方式,但两个版本都很好。你也可以删除你答案下的所有评论吗?为了更好的可读性,我已经删除了我的。@Peter我只是遵循了你在上面的if
中使用的早期退出模式(FWIW我自己更喜欢这种方法:)
const dispatch = useDispatch();
const popMessage = useCallback(id =>
dispatch(NotificationActions.popNotification(id))
, []);
const notifications = useSelector(state => state.notifications);
const previousValue = usePrevious(notifications.length);
useEffect(() => {
if (!notifications.length || previousValue >= notifications.length) return;
// Extract notification from list of notifications
const [notification] = notifications;
if (!notification) return;
popMessage(notification.id);
// Open snackbar
setSnackbar({
open: true,
message: notification.text,
variant: notification.variant,
});
}, [notifications]);