3
votes

I have this useEffect hook:

useEffect(() => {
  setTop(t => t + (controller.position.y * tileSize))
  setLeft(l => l + (controller.position.x * tileSize))
}, [controller.position])

I want it to only do the addition if the position changes. If the tileSize changes I just want it to do the multiplication.

I tried putting it in two useEffect but then I get the React Hook useEffect has missing dependencies warning:

useEffect(() => {
    setTop(t => t + (controller.position.y * spriteSize))
    setLeft(l => l + (controller.position.x * spriteSize))
}, [controller.position])

useEffect(() => {
    setTop((controller.position.y * spriteSize))
    setLeft((controller.position.x * spriteSize))
}, [spriteSize])

What's the best practice in this case?

EDIT:

A reproducible example:

const [tileSize, setTileSize] = useState(0)
const controller = {
    position: {
        x: 0,
        y: 0
    }
}
useEffect(() => {
    setTop(t => t + (controller.position.y * tileSize))
    setLeft(l => l + (controller.position.x * tileSize))
}, [controller.position])

useEffect(() => {
    setTop((controller.position.y * tileSize))
    setLeft((controller.position.x * tileSize))
}, [tileSize])

const asdf = () => {
    setTileSize(150)
}

return (
    <div onClick={() => asdf()}>click me</div>
)

Warning message:

Line 31: React Hook useEffect has a missing dependency: 'tileSize'. Either include it or remove the dependency array. You can also replace multiple useState variables with useReducer if 'setTop' needs the current value of 'tileSize' react-hooks/exhaustive-deps

Line 36: React Hook useEffect has missing dependencies: 'controller.position.x' and 'controller.position.y'. Either include them or remove the dependency array react-hooks/exhaustive-deps Line 46: Unreachable code no-unreachable

1
Did you set [tileSize] in second useEffect hook?DedaDev
@Deda Yes, so it would complain about position in one of the useEffect hooks and then complain about tileSize in the other.dan-klasson
Please show whole code / reproducible exampleDennis Vash
@DennisVash Updated. Both variables are coming from context API hooks. You need that too?dan-klasson
@DennisVash: Added a reproducible exampledan-klasson

1 Answers

1
votes

There are many approaches, you should peek the most readable one for your use case.

  1. As the warning suggests, replace with useReducer

React Hook useEffect has a missing dependency: 'tileSize'. Either include it or remove the dependency array. You can also replace multiple useState variables with useReducer if 'setTop' needs the current value of 'tileSize'. (react-hooks/exhaustive-deps)

const STATE = {
  ADDITION: 'addition',
  MULTIPLICATION: 'multiplication'
};

function reducer(state, action) {
  switch (action.type) {
    case STATE.ADDITION:
      return {
        ...state,
        position: action.position,
        top: state.top + action.position * state.spriteSize
      };
    case STATE.MULTIPLICATION:
      return {
        ...state,
        spriteSize: action.spriteSize,
        top: state.position * action.spriteSize
      };
    default:
      throw new Error();
  }
}

function Controller({ position, spriteSize }) {
  const [state, dispatch] = useReducer(reducer, {
    top: 0,
    position,
    spriteSize
  });

  useEffect(() => {
    dispatch({ type: STATE.ADDITION, position });
  }, [position]);

  useEffect(() => {
    dispatch({ type: STATE.MULTIPLICATION, spriteSize });
  }, [spriteSize]);

  return <FlexBox>{state.top}</FlexBox>;
}
  1. You can use references useRef and compare with older values
  2. If you know what you are doing, just disable the lint warning.

Edit styled-antd-react-starter