将生命周期方法反应到钩子

Wil*_*ack 6 javascript reactjs react-hooks

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

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;
}
Run Code Online (Sandbox Code Playgroud)

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

//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();
  }, []);

Run Code Online (Sandbox Code Playgroud)
  1. 我收到错误 - “重新渲染太多。” 在codeandbox完整代码: codesandbox

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

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

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

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

Mhm*_*z_A 3

没有依赖关系的效果是"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);
  })
Run Code Online (Sandbox Code Playgroud)

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

//componentDidUpdate
  useEffect(() => {
    ...
    setIsloading(false);
  },[isLoading]);
Run Code Online (Sandbox Code Playgroud)

您还可以将两个安装效果合并为一个,如下所示(您的也可以工作,但我认为这在风格上更可取):

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

    //componentWillUnmount
    return function () {
      props.onUnload()
    }
  }, []);
Run Code Online (Sandbox Code Playgroud)

第二个要点:关于重写组件的shouldComponentUpdate; 首先我必须指出,您现有的shouldComponentUpdate听起来并不合理,因为您总是 return true,并且您只是用它来触发loading状态;并且它不适合用React.memo编写(相当于shouldComponentUpdate类组件);因此,您只需要在每次 props 更改时执行一些操作来确定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 
Run Code Online (Sandbox Code Playgroud)

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