Home > Back-end >  React custom hook vs useReducer
React custom hook vs useReducer

Time:10-08

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)

CodePudding user response:

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.

CodePudding user response:

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.

  • Related