gpt4 book ai didi

javascript - Webpack 热模块替换,react 18 ReactDOMClient.createRoot() 在之前已经传给 createRoot() 的容器上

转载 作者:行者123 更新时间:2023-12-05 00:28:47 24 4
gpt4 key购买 nike

我将 React 更新到 v18,每当热模块替换触发并注入(inject)新的 javascript 代码时,我的 Webpack 开发服务器都会给我一个控制台错误:Warning: You are calling ReactDOMClient.createRoot() on a container that has already been passed to createRoot() before. Instead, call root. render() on the existing root instead if you want to update it.index.js文件

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.jsx';

const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);

root.render(<App />);

if (module.hot) module.hot.accept(function (err) {
console.log('An error occurred while accepting new version');
});
webpack.config.js
const path = require('path');
const HtmlWEbpackPlugin = require('html-webpack-plugin');

module.exports = (env) => {
let cfg = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.[contenthash:6].js',
publicPath: '/',
clean: true
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
]
},
plugins: [new HtmlWEbpackPlugin({ template: './src/index.html' })
],
devServer: {
static: {
directory: path.join(__dirname, 'public'),
},
compress: true,
port: 3000,
hot: true,
open: true,

},
performance: {
hints: false
}

}

return cfg;
};

最佳答案

React 18 原生支持热重载,这称为快速刷新。摘自 react-refresh自述文件:
快速刷新是一项功能,可让您在运行的应用程序中编辑 React 组件而不会丢失其状态。它类似于一个被称为“热重载”的旧功能,但快速刷新更可靠,并且得到了 React 的官方支持。
要在 Webpack 5 中使用它,您需要一个名为 react-refresh-webpack-plugin 的插件。 .为了让它工作,我建议查看 git 存储库中包含的示例,尤其是 webpack-dev-server例子。
注意:在撰写此答案时,react-refresh-webpack-plugin处于实验状态,但 create-react-app已经在使用它,所以它可能足够稳定可以使用。
以下内容直接取自 react-refresh-webpack-pluginwebpack-dev-server例子:src/index.js

import { createRoot } from 'react-dom/client';
import App from './App';

const container = document.getElementById('app');
const root = createRoot(container);
root.render(<App />);
webpack.config.js
const path = require('path');
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const isDevelopment = process.env.NODE_ENV !== 'production';

module.exports = {
mode: isDevelopment ? 'development' : 'production',
devServer: {
client: { overlay: false },
},
entry: {
main: './src/index.js',
},
module: {
rules: [
{
test: /\.jsx?$/,
include: path.join(__dirname, 'src'),
use: 'babel-loader',
},
],
},
plugins: [
isDevelopment && new ReactRefreshPlugin(),
new HtmlWebpackPlugin({
filename: './index.html',
template: './public/index.html',
}),
].filter(Boolean),
resolve: {
extensions: ['.js', '.jsx'],
},
};
babel.config.js
module.exports = (api) => {
// This caches the Babel config
api.cache.using(() => process.env.NODE_ENV);
return {
presets: [
'@babel/preset-env',
// Enable development transform of React with new automatic runtime
['@babel/preset-react', { development: !api.env('production'), runtime: 'automatic' }],
],
// Applies the react-refresh Babel plugin on non-production modes only
...(!api.env('production') && { plugins: ['react-refresh/babel'] }),
};
};
您可以从 Webpack 入口点中删除以下内容: src/index.js
// ...
if (module.hot) {
module.hot.accept()
}
这有一个小缺点,即每当您修改入口点 ( src/index.js) 时,都需要完全重新加载。 Webpack 非常反对您需要完全重新加载,向您显示以下日志消息。
[image]
这真的让我很生气。当查看如何 create-react-app解决了这个问题,我发现他们禁用了 webpack-dev-server 的客户端日志记录。 ,或者至少将日志级别设置为 warnerror .您可以通过设置 client.logging 来设置日志级别 devServer 中的属性(property)配置: webpack.config.js
// ...
devServer: {
client: {
overlay: false,
logging: 'warn' // Want to set this to 'warn' or 'error'
}
}
// ...
“警告”的奇怪之处在于,它根本不是警告,只是伪装成警告的信息信息。
希望这可以帮助。

关于javascript - Webpack 热模块替换,react 18 ReactDOMClient.createRoot() 在之前已经传给 createRoot() 的容器上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71719220/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com