Skip to main content
Active reading [<https://en.wiktionary.org/wiki/this#Determiner> <https://en.wikipedia.org/wiki/React_(JavaScript_library)> <https://www.youtube.com/watch?v=1Dax90QyXgI&t=17m54s>]. Brevity. Dressed the naked link.
Source Link
Peter Mortensen
  • 31.2k
  • 22
  • 110
  • 134

The closure is not the only reason.

Based on the source code of useState (simplified below). Seems, it seems to me the value is never assigned right away.

What happens is that anAn update action is queued when you invoke setValue. And after the schedule kicks in and only when you get to the next render, thesethis update action then is applied to that state.

Which means even if we don't have a closure issue, reactthe React version of useState is not going to give you the new value right away. The new value doesn't even exist until next render.

  function useState(initialState) {
    let hook;
    ...

    let baseState = hook.memoizedState;
    if (hook.queue.pending) {
      let firstUpdate = hook.queue.pending.next;

      do {
        const action = firstUpdate.action;
        baseState = action(baseState);            // setValue HERE
        firstUpdate = firstUpdate.next;
      } while (firstUpdate !== hook.queue.pending);

      hook.queue.pending = null;
    }
    hook.memoizedState = baseState;

    return [baseState, dispatchAction.bind(null, hook.queue)];
  }

function dispatchAction(queue, action) {
  const update = {
    action,
    next: null
  };
  if (queue.pending === null) {
    update.next = update;
  } else {
    update.next = queue.pending.next;
    queue.pending.next = update;
  }
  queue.pending = update;

  isMount = false;
  workInProgressHook = fiber.memoizedState;
  schedule();
}
 

There's also an article explaining the above in the similar way, https://dev.to/adamklein/we-don-t-know-how-react-state-hook-works-1lp8We don't know how React state hook works

The closure is not the only reason.

Based on the source code of useState (simplified below). Seems to me the value is never assigned right away.

What happens is that an update action is queued when you invoke setValue. And after the schedule kicks in and only when you get to the next render, these update action then is applied to that state.

Which means even we don't have closure issue, react version of useState is not going to give you the new value right away. The new value doesn't even exist until next render.

  function useState(initialState) {
    let hook;
    ...

    let baseState = hook.memoizedState;
    if (hook.queue.pending) {
      let firstUpdate = hook.queue.pending.next;

      do {
        const action = firstUpdate.action;
        baseState = action(baseState);            // setValue HERE
        firstUpdate = firstUpdate.next;
      } while (firstUpdate !== hook.queue.pending);

      hook.queue.pending = null;
    }
    hook.memoizedState = baseState;

    return [baseState, dispatchAction.bind(null, hook.queue)];
  }

function dispatchAction(queue, action) {
  const update = {
    action,
    next: null
  };
  if (queue.pending === null) {
    update.next = update;
  } else {
    update.next = queue.pending.next;
    queue.pending.next = update;
  }
  queue.pending = update;

  isMount = false;
  workInProgressHook = fiber.memoizedState;
  schedule();
}
 

There's also an article explaining the above in the similar way, https://dev.to/adamklein/we-don-t-know-how-react-state-hook-works-1lp8

The closure is not the only reason.

Based on the source code of useState (simplified below), it seems to me the value is never assigned right away.

An update action is queued when you invoke setValue. And after the schedule kicks in and only when you get to the next render, this update action then is applied to that state.

Which means even if we don't have a closure issue, the React version of useState is not going to give you the new value right away. The new value doesn't even exist until next render.

  function useState(initialState) {
    let hook;
    ...

    let baseState = hook.memoizedState;
    if (hook.queue.pending) {
      let firstUpdate = hook.queue.pending.next;

      do {
        const action = firstUpdate.action;
        baseState = action(baseState);            // setValue HERE
        firstUpdate = firstUpdate.next;
      } while (firstUpdate !== hook.queue.pending);

      hook.queue.pending = null;
    }
    hook.memoizedState = baseState;

    return [baseState, dispatchAction.bind(null, hook.queue)];
  }

function dispatchAction(queue, action) {
  const update = {
    action,
    next: null
  };
  if (queue.pending === null) {
    update.next = update;
  } else {
    update.next = queue.pending.next;
    queue.pending.next = update;
  }
  queue.pending = update;

  isMount = false;
  workInProgressHook = fiber.memoizedState;
  schedule();
}

There's also an article explaining the above in the similar way, We don't know how React state hook works

a link
Source Link
windmaomao
  • 7.7k
  • 2
  • 37
  • 38

The closure is not the only reason.

Based on the source code of useState (simplified below). Seems to me the value is never assigned right away.

What happens is that an update action is queued when you invoke setValue. And after the schedule kicks in and only when you get to the next render, these update action then is applied to that state.

Which means even we don't have closure issue, react version of useState is not going to give you the new value right away. The new value doesn't even exist until next render.

  function useState(initialState) {
    let hook;
    ...

    let baseState = hook.memoizedState;
    if (hook.queue.pending) {
      let firstUpdate = hook.queue.pending.next;

      do {
        const action = firstUpdate.action;
        baseState = action(baseState);            // setValue HERE
        firstUpdate = firstUpdate.next;
      } while (firstUpdate !== hook.queue.pending);

      hook.queue.pending = null;
    }
    hook.memoizedState = baseState;

    return [baseState, dispatchAction.bind(null, hook.queue)];
  }

function dispatchAction(queue, action) {
  const update = {
    action,
    next: null
  };
  if (queue.pending === null) {
    update.next = update;
  } else {
    update.next = queue.pending.next;
    queue.pending.next = update;
  }
  queue.pending = update;

  isMount = false;
  workInProgressHook = fiber.memoizedState;
  schedule();
}

There's also an article explaining the above in the similar way, https://dev.to/adamklein/we-don-t-know-how-react-state-hook-works-1lp8

The closure is not the only reason.

Based on the source code of useState (simplified below). Seems to me the value is never assigned right away.

What happens is that an update action is queued when you invoke setValue. And after the schedule kicks in and only when you get to the next render, these update action then is applied to that state.

Which means even we don't have closure issue, react version of useState is not going to give you the new value right away. The value doesn't even exist until next render.

  function useState(initialState) {
    let hook;
    ...

    let baseState = hook.memoizedState;
    if (hook.queue.pending) {
      let firstUpdate = hook.queue.pending.next;

      do {
        const action = firstUpdate.action;
        baseState = action(baseState);            // setValue HERE
        firstUpdate = firstUpdate.next;
      } while (firstUpdate !== hook.queue.pending);

      hook.queue.pending = null;
    }
    hook.memoizedState = baseState;

    return [baseState, dispatchAction.bind(null, hook.queue)];
  }

function dispatchAction(queue, action) {
  const update = {
    action,
    next: null
  };
  if (queue.pending === null) {
    update.next = update;
  } else {
    update.next = queue.pending.next;
    queue.pending.next = update;
  }
  queue.pending = update;

  isMount = false;
  workInProgressHook = fiber.memoizedState;
  schedule();
}

The closure is not the only reason.

Based on the source code of useState (simplified below). Seems to me the value is never assigned right away.

What happens is that an update action is queued when you invoke setValue. And after the schedule kicks in and only when you get to the next render, these update action then is applied to that state.

Which means even we don't have closure issue, react version of useState is not going to give you the new value right away. The new value doesn't even exist until next render.

  function useState(initialState) {
    let hook;
    ...

    let baseState = hook.memoizedState;
    if (hook.queue.pending) {
      let firstUpdate = hook.queue.pending.next;

      do {
        const action = firstUpdate.action;
        baseState = action(baseState);            // setValue HERE
        firstUpdate = firstUpdate.next;
      } while (firstUpdate !== hook.queue.pending);

      hook.queue.pending = null;
    }
    hook.memoizedState = baseState;

    return [baseState, dispatchAction.bind(null, hook.queue)];
  }

function dispatchAction(queue, action) {
  const update = {
    action,
    next: null
  };
  if (queue.pending === null) {
    update.next = update;
  } else {
    update.next = queue.pending.next;
    queue.pending.next = update;
  }
  queue.pending = update;

  isMount = false;
  workInProgressHook = fiber.memoizedState;
  schedule();
}

There's also an article explaining the above in the similar way, https://dev.to/adamklein/we-don-t-know-how-react-state-hook-works-1lp8

Source Link
windmaomao
  • 7.7k
  • 2
  • 37
  • 38

The closure is not the only reason.

Based on the source code of useState (simplified below). Seems to me the value is never assigned right away.

What happens is that an update action is queued when you invoke setValue. And after the schedule kicks in and only when you get to the next render, these update action then is applied to that state.

Which means even we don't have closure issue, react version of useState is not going to give you the new value right away. The value doesn't even exist until next render.

  function useState(initialState) {
    let hook;
    ...

    let baseState = hook.memoizedState;
    if (hook.queue.pending) {
      let firstUpdate = hook.queue.pending.next;

      do {
        const action = firstUpdate.action;
        baseState = action(baseState);            // setValue HERE
        firstUpdate = firstUpdate.next;
      } while (firstUpdate !== hook.queue.pending);

      hook.queue.pending = null;
    }
    hook.memoizedState = baseState;

    return [baseState, dispatchAction.bind(null, hook.queue)];
  }

function dispatchAction(queue, action) {
  const update = {
    action,
    next: null
  };
  if (queue.pending === null) {
    update.next = update;
  } else {
    update.next = queue.pending.next;
    queue.pending.next = update;
  }
  queue.pending = update;

  isMount = false;
  workInProgressHook = fiber.memoizedState;
  schedule();
}