0

I have created my own React Hook, but i have the React Hook useEffect has a missing dependency: 'setPlayer'. Either include it or remove the dependency array warning, when i'm using the function from my custom hook. I tried to extract the function from the hook to avoid React to creates a new function instance at each render, also tried useCallback, but still have the same issue.

When I'm using useReducer I can use dispatch in my useEffect without any warning, what is the difference exactly ?

my custom hook with the warning :


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

}

Also tried:

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

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

For instance when i'm using dispatch from useReducer I do not have this warning (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>
    </>
  );
}

How to implement the same kind of Hook (with no warning with my function) ? (tried to dig into the implementation, but no help https://github.com/facebook/react/blob/6ecad79ccf2c683cb21ac40dee5678358c7b6208/packages/react/src/ReactHooks.js#L24)

Limmy
  • 53
  • 12

2 Answers2

2

The error you're seeing is an eslint rule warning you about a missing dependency in a react hook dependency array. It's telling you that you should include setPlayer in your list of dependencies because it can't tell if it's a stable reference. The reason it doesn't complain about dispatch from useReducer is because useReducer and its functions are explicitly handled in the eslint rule. Eslint doesn't know your function is stable, but you do, so it's safe to put it in to the dependency array and silence the error.

Donovan Hiland
  • 1,439
  • 11
  • 18
  • Yes, but why it does not do the warning for `dispatch` of useReducef ? – Limmy Oct 07 '21 at 19:10
  • 1
    See the explanation: "The reason it doesn't complain about dispatch from useReducer is because useReducer and its functions are explicitly handled in the eslint rule". The react team wrote the eslint rule so they're ignoring that case explicitly – Donovan Hiland Oct 07 '21 at 19:19
  • Thanks, finally it's really verbose to write it everytime or embarrassing to have this warning, it there any way to avoid it ? – Limmy Oct 07 '21 at 20:25
  • You definitely don't want to ignore the warning, it's actually a good rule and generally very helpful. I don't think it's as bad as you think. If your hooks become so big that you feel it's extremely verbose to add a bunch of dependencies then maybe it's time to refactor/simplify/split some code up – Donovan Hiland Oct 08 '21 at 15:22
1

I don't know if this is the cause of your warning, but I can see a small mistake in your code. You are returning an array in your hook return [getPlayerService, setPlayer]. When trying to destructure it, you are doing it as if it's an object. With an object you can destructure it like you have done here const [setPlayer] = usePlayer(); because it's consisted of key value pairs ( also you should swap [] for {} ). But destructuring arrays, is based on their index and their sequence. So when you are getting only one of the items back, it would be the first item with index 0 in the array. So the setPlayer that you have destrutured is indeed your getPlayerService method.

Sobhan Jahanmard
  • 821
  • 5
  • 16