如何避免useEffect 执行两次

  const {keyword} = query
  const {page, pageSize} = table.pagination 

  useEffect(() => {
    setTable(prevState => ({
      ...prevState,
      pagination: {...prevState.pagination, page: 1}
    }))
  }, [keyword])

  useEffect(() => {
    fetchList()
  }, [page, pageSize, keyword])

表格改变查询条件时,需要将表格分页重置为第一页。但是fetchList会执行两次。
需要怎么做,才能让fetchList只执行一次

demo链接:https://codesandbox.io/s/obje...

阅读 17.2k
4 个回答

正确做法是不应该把重置为第一页这个事情写成一个effect…
如果你还有别的东西要重置(比如重置排序参数、重置分页大小),每个重置都单独写一个effect,那你可能不止重复渲染一次,而是重复渲染n次;

setState的时候自己手动去干这个事情而不是用effect去干;嫌麻烦可以把这个手动干的过程给封起来

/** @param init @param {(preState, nextState) => mergedSatte} onUpdate */
export function useStateWithCycle(init, onUpdate) {
    const [state, setState] = useState(init)
    function setStateWithCycle (nextState) {
        if (typeof nextState === 'function') {
            setState(pre => onUpdate( pre, nextState(pre) ))    
        } else {
            setState(pre => onUpdate( pre, nextState ))    
        }
    }

    return [state, setStateWithCycle]
}

首先,如果有合并机制,useEffect 的多个依赖项就没有意义,根据你的代码,keyword 切换仅仅对引起的 page 重置,看下面代码:

  const {keyword} = query
  const {page, pageSize} = table.pagination 

  useEffect(() => {
    if(!keyword) {
        return
    }
    if(page === 1) {
        fetchList()
    } else {
        setTable(prevState => ({
          ...prevState,
          pagination: {...prevState.pagination, page: 1}
        }))
    }
  }, [keyword])

  useEffect(() => {
    fetchList()
  }, [page, pageSize])

已经在你的 demo 上测试了,可以正常运行

方案之一:

 // useEffect(() => {
  //   setPagination((prevState) => ({ ...prevState, page: 1 }));
  // }, [keyword]);

  function handleInputChange(e) {
    const keyword = e.target.value;
    setQuery((prevState) => ({ ...prevState, keyword }))
    setPagination((prevState) => ({ ...prevState, page: 1 }));
  }

参考解密React state hook

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题