Skip to content

Bug: eager state miss #34061

@HHsomeHand

Description

@HHsomeHand
import React, { useState } from 'react';

export function App(props) {
  console.log('App');
  return <Child0 />;
}

function Child0(props) {
  let [state, setState] = useState(0);
  console.log('child0', state);
  return (
    <div onClick={() => setState(1)}>
      child0
      <Child1 />
    </div>
  );
}

function Child1(props) {
  console.log('child1');
  console.log('=======');
  return <div>child1</div>;
}

console:

App 
child0 0
child1 
=======  (first click)
child0 1
child1 
======= (second click) 
child0 1

(rest click: noop, eager state)

Strange, why is child0 1 printed one more time here?

Isn't there eager state? If the state hasn't changed, it shouldn't re-render, right?

I didn't use StrictMode

I debug react:

 function dispatchSetStateInternal(fiber, queue, action, lane) {
      var update = {
        lane: lane,
        revertLane: 0,
        action: action,
        hasEagerState: !1,
        eagerState: null,
        next: null
      };
      if (isRenderPhaseUpdate(fiber)) enqueueRenderPhaseUpdate(queue, update);
      else {
        var alternate = fiber.alternate;
        if (
          0 === fiber.lanes &&
          (null === alternate || 0 === alternate.lanes) &&
          ((alternate = queue.lastRenderedReducer), null !== alternate)
        ) {
          var prevDispatcher = ReactSharedInternals.H;
          ReactSharedInternals.H = InvalidNestedHooksDispatcherOnUpdateInDEV;
          try {
            var currentState = queue.lastRenderedState,
              eagerState = alternate(currentState, action);
            update.hasEagerState = !0;
            update.eagerState = eagerState;
            if (objectIs(eagerState, currentState))
              return (
                enqueueUpdate$1(fiber, queue, update, 0),
                null === workInProgressRoot &&
                  finishQueueingConcurrentUpdates(),
                !1
              );
          } catch (error) {
          } finally {
            ReactSharedInternals.H = prevDispatcher;
          }
        }
        action = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
        if (null !== action)
          return (
            scheduleUpdateOnFiber(action, fiber, lane),
            entangleTransitionUpdate(action, queue, lane),
            !0
          );
      }
      return !1;
    }

I'm not using concurrent rendering either—so why does the 0 === fiber.lanes check fail?

Isn't fiber.lanes supposed to be cleared after the update is finished?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Status: UnconfirmedA potential issue that we haven't yet confirmed as a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions