gaearon / react-hot-loader

Tweak React components in real time. (Deprecated: use Fast Refresh instead.)
http://gaearon.github.io/react-hot-loader/
MIT License
12.26k stars 801 forks source link

Component using hooks only hot-reloads the JSX, not the hooks' state #1167

Open resolritter opened 5 years ago

resolritter commented 5 years ago

Description

Continuing from https://github.com/gaearon/react-hot-loader/issues/1166.

Using this webpack configuration

rules: [
      {
        test: /\.jsx?$/,
        use: [
          {
            loader: "babel-loader",
            options: {
              cacheDirectory: true
            }
          },
          "react-hot-loader/webpack"
        ]
      },

React-Hot-Loader: react-🔥-dom patch detected. You may use all the features.

My component using hooks updates if I change the rendered content (what is returned), but not if I change the hooks' state itself.

function HelloReact() {
// 🔴 Changing state does NOT hot-reload the message
//                                        👇 
  const [message, setMessage] = useState('Niels')
  return (
//  Changing div or Hello hot-reloads the component but NOT the message
    <div className={styles['title']}>Hello {message}</div>
  );
}

I tried to mark hook components as cold, like this


  onComponentCreate: (type, name) => {
    if (!String(type).startsWith('function AppContainer()') && String(type).match(/use/)) {
      console.log(type)
    }
    return (!String(type).startsWith('function AppContainer()') && String(type).match(/use/)) ? cold(type) : type
  }

It seems to correctly mark them as cold, but doesn't change the state.

image

Environment

React Hot Loader version: 4.6.3

  1. Operating system: Ubuntu Linux
  2. Browser: Chrome

Reproducible Demo

https://github.com/reaysawa/saga-react-kit

theKashey commented 5 years ago

This is expected - ReactHotLoader could not change "the past".

  1. RHL is preserving a state, so it does not re-create component, doesn't call life-cycle methods, and so on.
  2. So it does not recreate state and hooks - everything continues where it was, with a state as it was.
  3. And anyway - RHL does not have access to hooks. We could not detect your change, even if we wanted to do it.

For now, and nearest future, that how it would work, there is nothing I could do.

natew commented 5 years ago

Could you not do a source comparison and if it differs reset the state? I did this in a hot loading setup previously and I liked it more than attempting to preserve state changes when source changed.

Usually was just upcomingComponent.constructor.toString() !== previousSource or similar.

theKashey commented 5 years ago

I could do it for classes not for hooks. As long as they got released I could try to look for a proper hooks for hooks. Probably it should be quite easy to properly destruct the old hooks(changed ones) and let the new ones to spin up.

yoution commented 5 years ago

I write a babel plugin for react hooks, it wrap hooks component with react component, https://github.com/yoution/babel-plugin-react-hooks-hot-load