Separating State Variables

If you're coming from classes, you might be tempted to always call useState() once and put all state into a single object:


RESETRUNFULL
function Box() {
  const [state, setState] = useState({ left: 0, top: 0, width: 100, height: 100 });  // ...}// ...
  useEffect(() => {
    function handleWindowMouseMove(e) {      // Spreading "...state" ensures we don't "lose" width and height
      setState(state => ({ ...state, left: e.pageX, top: e.pageY }));
    }    // Note: this implementation is a bit simplified
    window.addEventListener('mousemove', handleWindowMouseMove);
    return () => window.removeEventListener('mousemove', handleWindowMouseMove);
  }, []);// ...

Now with hooks you should, in general, split state into multiple state variables based on which values tend to change together:


RESETRUNFULL
function Box() {
  const [position, setPosition] = useState({ left: 0, top: 0 });
  const [size, setSize] = useState({ width: 100, height: 100 });
  useEffect(() => {
    function handleWindowMouseMove(e) {
      setPosition({ left: e.pageX, top: e.pageY });
    }    // ...

Not only does separating state variables make your code more readable and easier to manage. It also makes it easier to extract logic into a custom hook:


RESETRUNFULL
function Box() {
  const position = useWindowPosition();
  const [size, setSize] = useState({ width: 100, height: 100 });  // ...}function useWindowPosition() {
  const [position, setPosition] = useState({ left: 0, top: 0 });
  useEffect(() => {    // ...
  }, []);
  return position;}