cerebral/overmind

[BUG] React component doesn't rerender on state change

jmattheis opened this issue · 1 comments

In the example below overmind won't rerender SubComponent on state changes. When adding a useOvermindState all works fine. I guess it is because of the WrapChildren component. Overmind rerenders the WrapChildren component but this dosen't update children from the parent component which results in outdated values.

const WrapChildren: React.FC = ({ children }) => {
  const state = useOvermindState();

  return (
    <div>
      {state.demo.other}
      {children}
    </div>
  );
};

const SubComponent = ({
  value,
  setValue
}: {
  value: DemoState;
  setValue: (v: string) => void;
}) => {
  // with this everything works fine
  // useOvermindState()
  return (
    <div>
      <input value={value.name} onChange={(e) => setValue(e.target.value)} />
    </div>
  );
};

export const App = () => {
  const actions = useOvermindActions();
  const state = useOvermindState();

  return (
    <>
      <WrapChildren>
        <SubComponent
          value={state.demo}
          setValue={(newValue) => actions.demo.setName(newValue)}
        />
      </WrapChildren>
    </>
  );
};

In the example / CodeSandbox the it is not possible to write in the text input, because it doesn't receive the newer values.

CodeSandbox: https://codesandbox.io/s/overmind-no-react-rerender-k98d4

Going through and cleaning up issues. Looking at this, I think everything is behaving as expected:

  • You pass a reference to an object into Subcomponent
  • React's props comparator to determine re-render sees no change when you change a property of the object being passed in ( it's the same object ref- so it is determining no re-render is necessary)
  • If you change the value= prop passed in to a string/state.demo.name, then it works as expected because React does see a prop change
  • The reason it works with useOvermindState() uncommented is because you force overmind to track the component instead of relying on React to do it, thus overmind knows that component uses state and forces it to re-render

To see this for yourself, just add a console.log('render mycomp' ) to both the WrapChildren and Subcomponent, and you'll see which is re-rendering on text box change/action call. React does not re-render Sub even though it re-renders Wrap.

Closing this issue but reopen if you disagree?