Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

State isn't preserved #112

Closed
dmeij opened this issue Jun 10, 2020 · 6 comments
Closed

State isn't preserved #112

dmeij opened this issue Jun 10, 2020 · 6 comments

Comments

@dmeij
Copy link

dmeij commented Jun 10, 2020

I have made a demo site with the following config:

const ReactRefreshPlugin 	= require('@pmmmwh/react-refresh-webpack-plugin');
const HtmlWebpackPlugin 	= require('html-webpack-plugin');

module.exports = {
	entry: './src/index.js',
	mode: 'development',
	devtool: 'eval-cheap-module-source-map',
	devServer: {
		port: 12345,
		host: 'test.domain.com',
		watchOptions: {
			ignored: /node_modules/
		},
	},
	module: {
			rules: [
				{
					test: /\.jsx$/,
					exclude: /(node_modules|bower_components)/,
					use: [{
						loader: 'babel-loader',
						options: {
							presets: ['@babel/preset-react'],
							plugins: ['@babel/plugin-proposal-class-properties', '@babel/plugin-proposal-export-default-from', 'react-refresh/babel',],
						}
					}]
				},
			]
	},
	plugins: [new ReactRefreshPlugin(), new HtmlWebpackPlugin({template: './src/index.html', filename: 'test.html'}), ],
	resolve: {
	    extensions: ['.js', '.jsx'],
	  },
}

The port and host is dummy in above example. I have taken the files from the example dir https://github.com/pmmmwh/react-refresh-webpack-plugin/tree/master/examples/webpack-dev-server. When I change a file like ClassNamed.js, the output in the browser is refreshed without a page refresh. But the state is cleared, I think because the constructor of ClassNamed is called again. I don't think this is the indented behavior, but what am I doing wrong?

I'm using these versions:
"react": "^16.13.1",
"webpack-dev-server": "^3.11.0",
"react-refresh": "^0.8.3",
"@pmmmwh/react-refresh-webpack-plugin": "^0.3.3",

Hope someone can help!

@pmmmwh
Copy link
Owner

pmmmwh commented Jun 10, 2020

Class Components don't preserve state. This is intended behaviour.

@pmmmwh pmmmwh closed this as completed Jun 10, 2020
@dmeij
Copy link
Author

dmeij commented Jun 11, 2020

That's a shame, then i'm forced to use hot reloading :(. Why is this the intended behaviour? It's possible with hot reloading.

@pmmmwh
Copy link
Owner

pmmmwh commented Jun 11, 2020

Why is this the intended behaviour?

Class components are always remounted, and thus they can never preserve state. Fast refresh is implemented differently to react-hot-loader, and the fundamental difference means that some stuff people expect from RHL might not hold. This is one example of such things.

It's possible with hot reloading.

I'm assuming that you're referring to react-hot-loader.

There is a difference between "it is possible" and "it is reliable", and the line is often blurry. Hot reloading class components was never reliable/maintainable (components might end up in an incorrect state) and it requires mutation to your source code (wrapping components with Proxies). This causes a lot of stuff to not work properly: lifecycle methods being called randomly, type checks fails randomly (<Component />.type === Component is false). Not to mention that this approach peeks into React's internals, thus will need to play catch up with React as we move into the future with Concurrent Mode.

With all that background in mind, I don't think it is surprising that Dan chose to not let history repeats itself (especially when function components are getting more and more powerful with Hooks). In his wish list for hot reloading (which eventually led to Fast Refresh), he clearly stated:

It is better to lose local state than to behave incorrectly.
It is better to lose local state than use an old version.

However - I would suggest you still go with fast refresh instead of adopting RHL if you're planning to move to hooks in the future. While it will not preserve state for classes, fast refresh is much more reliable and resilient to errors, and will recover correctly in most cases. It is also officially stated in the RHL README that fast refresh should be the way to go moving forward.

I hope this better explains the situation.

@dmeij
Copy link
Author

dmeij commented Jun 11, 2020

Yes thanks for the clarification. I have a complete application based on Class Components, it's not an option to convert it to Function Components. Developing with Class Components and using Fast Refresh would seem frustrating to me, because you won't be able to preserve the state :(. I understand this will be the future, but I can't convert the current application to Function components, would take too much time.

Thnx again!

@dmeij
Copy link
Author

dmeij commented Jun 11, 2020

One more question though, hope you know an answer since you're the fast refresh master :P. fast refresh always remounts class components and always triggers the useEffect for function components. When the component does an API call to load data, I would like it to be called only once and not at every fast refresh. Is this possible?

@pmmmwh
Copy link
Owner

pmmmwh commented Jun 12, 2020

When the component does an API call to load data, I would like it to be called only once and not at every fast refresh. Is this possible?

It is not possible - see the React Native Docs for a more thorough explanation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants