【问题标题】:componentDidUpdate Conversion to HookscomponentDidUpdate 转换为 Hooks
【发布时间】:2019-07-12 09:47:39
【问题描述】:

我想把这个生命周期方法改写成一个钩子:

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),还是不行。

【问题讨论】:

  • 不需要在你usePrevious的useEffect中加上[value]吗?像这样的东西:useEffect(() => { ... }, [value])。同样在其他useEffect中,我认为您应该将[notifications]添加到您的useEffect中。至少这不应该比旧的更被调用。
  • 看看usePrevious这里:usehooks.com/usePrevious

标签: reactjs react-redux material-ui react-hooks


【解决方案1】:

几个问题我可以在你的 Hook 代码中看到一个问题:

  1. usePrevious 永远不会更新超过第一个值集

    useEffect 中没有设置依赖项时,它只运行一次。在你的情况下,因为你想跟踪最后一个值集,你需要使它成为useEffect 的依赖项,即useEffect(() => ..., [value]),这将强制回调重新运行并更新参考。

    原来我误解了,当函数组件重新渲染时,它会重新运行钩子的效果,你可以忽略第 1 点。

  2. useEffect里面的主要更新代码,和第1点类似,只会运行一次。

    同样,当通知计数发生变化时,代码预计会重新运行,因此需要将其设置为依赖项useEffect(() => ..., [notifications.length])

至于您提到的错误-notification is undefined,这表明您的notifications 状态不是有效数组或数组为空,请检查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]);

【讨论】:

  • 好吧,感谢您更新答案并帮助我。我以不同的方式做到了,但两个版本都很好。您还可以删除答案下的所有cmets吗?为了更好的可读性,我已经删除了我的。
  • @Peter 我只是遵循了您在上面的if 中使用的相同的提前退出模式(FWIW 我自己更喜欢这种方法:))
【解决方案2】:

您可以使用第二个参数(变量数组)限制 useEffect 触发的时间。

useEffect(() => true, [variable]);

在第一次加载或变量值发生变化时,会触发使用效果,如果第二个参数不指定任何内容,则每次重新渲染都会触发使用效果。

【讨论】:

    【解决方案3】:

    要将componentDidUpdate 替换为useEffect 钩子,请将第二个参数传递给它,其中包含变量数组,该变量必须从这个渲染更改为下一个,以便钩子运行

    useEffect(() => {
    
      // your code
    
    },[props.notifications])
    
    

    【讨论】:

    • 对不起,我的错误。只需使用props.notifications
    猜你喜欢
    • 1970-01-01
    • 2019-12-20
    • 2021-12-29
    • 1970-01-01
    • 1970-01-01
    • 2021-03-10
    • 2021-05-30
    • 1970-01-01
    • 2021-04-10
    相关资源
    最近更新 更多