【问题标题】:React custom hook vs useReducerReact 自定义钩子与 useReducer
【发布时间】:2021-10-07 18:39:31
【问题描述】:

我已经创建了自己的 React Hook,但是当我使用自定义钩子中的函数时,我收到了 React Hook useEffect has a missing dependency: 'setPlayer'. Either include it or remove the dependency array 警告。 我试图从钩子中提取函数以避免 React 在每次渲染时创建一个新的函数实例,也尝试了useCallback,但仍然有同样的问题。

当我使用useReducer 时,我可以在我的useEffect 中使用dispatch 而不会发出任何警告,到底有什么区别?

带有警告的自定义钩子


export function usePlayer() {
  const playerService = useRef<PlayerService>();

  const setPlayer = useCallback((youtubePlayer: YouTubePlayer) => {
    playerService.current = new YoutubePlayerService(youtubePlayer);
  }, []);

  // also tried
  /**
    function setPlayer(youtubePlayer: YouTubePlayer) {
        playerService.current = new YoutubePlayerService(youtubePlayer);
    }
    and putting `setPlayer outside of the hook`
  **/

  const getPlayerService = useCallback(() => {
    return playerService.current;
  }, []);

  return [getPlayerService, setPlayer]
}

export function Component() {
  const [setPlayer] = usePlayer();
  const [youtubePlayer, setYoutubePlayer] = useState<YouTubePlayer>(undefined);


  useEffect(() => {
    setPlayer(youtubePlayer);
  }, [youtubePlayer]
      //React Hook useEffect has a missing dependency: 'setPlayer'. Either include it or remove the dependency array

}

也试过了:

let currentPlayerService = undefined;
function setPlayer(youtubePlayer: YouTubePlayer) {
  currentPlayerService = new YoutubePlayerService(youtubePlayer);
}

export function usePlayer() {
  return [currentPlayerService, setPlayer];
}

例如,当我使用 useReducer 中的 dispatch 时,我没有这个警告 (https://fr.reactjs.org/docs/hooks-reference.html#usereducer)

const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  useEffect(() => {
    dispatch({type: 'increment'})
  }, [state])
      // no warning with dispatch <<
  
  return (
    <>
      Total : {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

如何实现同一种 Hook(我的函数没有警告)? (试图深入研究实现,但没有帮助https://github.com/facebook/react/blob/6ecad79ccf2c683cb21ac40dee5678358c7b6208/packages/react/src/ReactHooks.js#L24

【问题讨论】:

    标签: javascript reactjs react-hooks use-reducer


    【解决方案1】:

    您看到的错误是一个 eslint 规则,警告您在反应挂钩依赖项数组中缺少依赖项。它告诉您应该在依赖项列表中包含 setPlayer,因为它无法判断它是否是稳定的引用。它之所以没有从useReducer 抱怨dispatch 是因为useReducer 和它的功能是explicitly handled in the eslint rule。 Eslint 不知道你的函数是稳定的,但你知道,所以将它放入依赖数组并消除错误是安全的。

    【讨论】:

    • 是的,但是为什么它没有对 useReducef 的dispatch 发出警告?
    • 查看解释:“它不抱怨从 useReducer 调度的原因是因为 useReducer 及其功能在 eslint 规则中明确处理”。 react 团队编写了 eslint 规则,因此他们明确地忽略了这种情况
    • 谢谢,终于每次都写太啰嗦了或者有这个警告很尴尬,有什么办法可以避免吗?
    • 您绝对不想忽略警告,这实际上是一个很好的规则,通常非常有用。我不认为它像你想的那么糟糕。如果你的钩子变得如此之大以至于你觉得添加一堆依赖项非常冗长,那么也许是时候重构/简化/拆分一些代码了
    【解决方案2】:

    我不知道这是否是您发出警告的原因,但我可以在您的代码中看到一个小错误。您在钩子 return [getPlayerService, setPlayer] 中返回一个数组。当你试图解构它时,你是在做它,就好像它是一个对象一样。使用对象,您可以像在 const [setPlayer] = usePlayer(); 中所做的那样对其进行解构,因为它由键值对组成(您也应该将 [] 交换为 {} )。但是解构数组是基于它们的索引和它们的顺序。因此,当您只取回一个项目时,它将是数组中索引为 0 的第一个项目。所以你解构的 setPlayer 确实是你的 getPlayerService 方法。

    【讨论】:

      猜你喜欢
      • 2022-01-24
      • 2019-12-09
      • 2021-05-10
      • 1970-01-01
      • 1970-01-01
      • 2022-01-10
      • 2020-08-27
      • 2020-11-02
      • 2020-08-09
      相关资源
      最近更新 更多