首页 > 解决方案 > 将生命周期方法反应到钩子

问题描述

我有简单的博客文章。我想将类重写为功能组件和钩子。现在,我在具有编辑/添加表单的页面的生命周期方法中得到了这个逻辑:它工作正常。

componentDidUpdate(prevProps, prevState) {
 if (this.props.match.params.id !== prevProps.match.params.id) {
    if (prevProps.match.params.id) {
        this.props.onUnload();
      }

      this.id = this.props.match.params.id;
        if (this.id) {
            return this.props.onLoad(userService.articles.get(this.id));
        }
        this.props.onLoad(null);
   }
   this.isLoading = false;
}

componentDidMount() {
  if (this.id) {
    this.isLoading = true;
    return this.props.onLoad(userService.articles.get(this.id));
  }
  this.isLoading = false;
  this.props.onLoad(null);
}
   
componentWillUnmount() {
   this.props.onUnload();
}
   
shouldComponentUpdate(newProps, newState) {
   if (this.props.match.params.id !== newProps.match.params.id) {
      this.isLoading = true;
   }
   return true;
}

我把它全部改写成这样的钩子:

//componentDidMount
  useEffect(() => {
    if (id) {
      setIsloading(true);
      return props.onLoad(userService.articles.get(id));
    }
    setIsloading(false);
    props.onLoad(null);
  }, []);

  useEffect(()=> {
      prevId.current = id;
      }, [id]
  );

  //componentDidUpdate
  useEffect(() => {
    //const id = props.match.params.id;
    if (id !== prevId.current) {
      if (prevId.current) {
        props.onUnload();
      }
      if (id) {
        return props.onLoad(userService.articles.get(id));
      }
      props.onLoad(null);
    }
    setIsloading(false);
  });

  //componentWillUnmount
  useEffect(() => {
     return props.onUnload();
  }, []);

  1. 我收到错误 - “重新渲染太多。” 在codesandbox完整代码: codesandbox

这很奇怪,但在本地主机上没有错误“重新渲染太多”。

  1. 不知道如何处理我的类“shouldComponentUpdate”方法如何将其重写为钩子。尝试了“备忘录”,但不知道在这种情况下如何写。

  2. 无论如何,我错过了一些东西,因为这一切都行不通——它没有正确更新表单字段。

如果您对反应挂钩有很好的了解,请提供帮助或提供一些建议 - 如何解决?

标签: javascriptreactjsreact-hooks

解决方案


没有依赖关系的效果是"Too many re-renders.":它在每次渲染后运行,然后调用setIsLoading更新 state( loading),这将导致组件重新渲染,它将再次运行,effect并且setState将再次调用effect等等......

//componentDidUpdate
  useEffect(() => {
    //const id = props.match.params.id;
    if (id !== prevId.current) {
      if (prevId.current) {
        props.onUnload();
      }
      if (id) {
        return props.onLoad(userService.articles.get(id));
      }
      props.onLoad(null);
    }
    setIsloading(false);
  })

要解决此问题,要么setIsLoading从中删除,要么添加IsLoading为依赖项。

//componentDidUpdate
  useEffect(() => {
    ...
    setIsloading(false);
  },[isLoading]);

您也可以像这样将两个安装效果合并为一个(您的也可以使用,但我认为这在风格上更可取):

//componentDidMount
  useEffect(() => {
    if (id) {
      setIsloading(true);
      return props.onLoad(userService.articles.get(id));
    }
    setIsloading(false);
    props.onLoad(null);

    //componentWillUnmount
    return function () {
      props.onUnload()
    }
  }, []);

对于第二个项目符号:关于重写组件的shouldComponentUpdate; 首先我必须指出你的存在shouldComponentUpdate听起来不合理,因为你总是 return true,你只是用它来触发loading状态;并且它不符合使用React.memo编写的条件(相当于shouldComponentUpdate类组件);因此,您只需要在每次道具更改时执行某些操作即可确定loading状态,为此您可以使用效果props作为其依赖项,如下所示:

//manually keeping old props id
const prevPropsId = useRef();

useEffect(() => {
   if (prevPropsId.current !== props.match.params.id) {
      setIsLoading(true);
   }
   prevPropsId.current = props.match.params.id;
 }, [props.match.params.id]);
// this hook only run if `props.match.params.id` change 

根据我的认识,这应该可以完成工作,(尽管很难理解为什么你首先要以这种方式编写逻辑),如果它做得不好,你可以稍微调整逻辑以满足你的需求,你会得到了解道具更改效果如何工作。还有很多人需要处理typeError以防万一idparams或者match不存在, 可选链接在这里可以是方便的工具->props.match?.params?.id


推荐阅读