HerbCaudill / react-redux-worker

Run a Redux store in a Web Worker.
10 stars 2 forks source link

ProxyProvider - Components re-renders even without any related state change #4

Open entrptaher opened 4 years ago

entrptaher commented 4 years ago

Assuming the StaticTitle does not have any useDispatch or useSelector, the component still re-renders.

While it does save us by moving everything to webworker, we lose the performance on re-rendering, imagine rendering a 200 row table or a huge page with lots of components, it's gonna put a huge impact and we lose any optimization this package gives us.

const StaticTitle = () => <h1>Redux Example</h1>;

const App = () => {
  return (
    <ProxyProvider>
        <StaticTitle />
        <Title />
        <Form />
    </ProxyProvider>
  );
};

Meanwhile, using the raw Provider from react-redux does not re-render this component.

const App = () => {
  return (
    <Provider store={store}>
        <StaticTitle />
        <Title />
        <Form />
    </Provider>
  );
};

React.memo doesn't work as well. It just re-renders forcefully.

Example using react devtools. image

Reproducable repository: https://github.com/entrptaher/exp-redux-worker Reproducable link: https://entrptaher.github.io/exp-redux-worker/

HerbCaudill commented 4 years ago

@entrptaher Hi - thanks for trying this out, and for documenting the problem so thoroughly! Sorry I didn't notice your message earlier.

As far as I can tell, StaticTitle isn't actually rerendering. I don't use React Dev Tools very often, and at any rate it looks like it no longer highlights renders? So here's what I tried: I've added logging to each component, so we see every time it renders.

// NOTE: this component should not re-render
const StaticTitle = () => {
  console.log("rendering StaticTitle");
  return <h1>Static Text</h1>;
};

const Title = (props) => {
  console.log("rendering Title");
  const title = useSelector((store) => store.title);
  return <div>{title}</div>;
};

const Form = (props) => {
  console.log("rendering Form");
  const title = useSelector((store) => store.title);
  const dispatch = useDispatch();
  const onChange = (event) => dispatch(actions.updateTitle(event.target.value));
  return (
    <div>
      <input value={title} onChange={onChange} />
    </div>
  );
};

const App = () => {
  return (
    <ProxyProvider>
      <StaticTitle />
      <Title />
      <Form />
    </ProxyProvider>
  );
};

This is what I see in the console as I type:

rendering StaticTitle
rendering Title
rendering Form
rendering Title
rendering Form
rendering Title
rendering Form
rendering Title
rendering Form
rendering Title
rendering Form
rendering Title
rendering Form

image

Am I missing something?

entrptaher commented 4 years ago

Devtools will highlight renders when you turn this on, image