为啥在 Redux-DevTools 中使用 Webpack HMR 插件时 App 状态会重置?

Posted

技术标签:

【中文标题】为啥在 Redux-DevTools 中使用 Webpack HMR 插件时 App 状态会重置?【英文标题】:Why does App state resets when using Webpack HMR plugin with Redux- DevTools?为什么在 Redux-DevTools 中使用 Webpack HMR 插件时 App 状态会重置? 【发布时间】:2016-10-22 18:13:09 【问题描述】:

我正在使用带有 Redux Devtools Chrome 扩展的 webpack Hot Module Replacement(HMR) 插件。但是,每当 HMR 运行时,Redux 本地应用程序状态都会重置为所有初始值。我的网络配置如下:

import webpack from 'webpack'
import path from 'path'
import htmlWebpackPlugin from 'html-webpack-plugin'

const LAUNCH_COMMAND = process.env.npm_lifecycle_event

const isProduction = LAUNCH_COMMAND === 'production'
process.env.BABEL_ENV = LAUNCH_COMMAND

const PATHS = 
  app: path.join(__dirname, 'app'),
  build: path.join(__dirname, 'dist')


const HTMLWebpackPluginConfig = new HtmlWebpackPlugin(
  template: PATHS.app + '/index.html',
  filename: 'index.html',
  inject: 'body'
)

const productionPlugin = new webpack.DefinePlugin(
  'process.env': 
    NODE_ENV: JSON.stringify('production')
  
)

const productionPlugin2 = new webpack.optimize.UglifyJsPlugin(
  compressor: 
    warnings: false
  
)

const base = 
  entry: [
    'babel-polyfill',
    PATHS.app
  ],
  output: 
    path: PATHS.build,
    filename: 'index_bundle.js'
  ,
  module: 
    loaders: [
      test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader',
      test: /\.css$/, loader: 'style!css?sourceMap&modules&localIdentName=[name]__[local]___[hash:base64:5]'
    ]
  ,
  resolve: 
    root: path.resolve('./app')
  


const developmentConfig = 
  devtool: 'cheap-module-inline-source-map',
  devServer: 
    contentBase: PATHS.build,
    historyApiFallback: true,
    hot: true,
    inline: true,
    progress: true
  ,
  plugins: [HTMLWebpackPluginConfig, new webpack.HotModuleReplacementPlugin()]


const productionConfig = 
  devtool: 'cheap-module-source-map',
  plugins: [HTMLWebpackPluginConfig, productionPlugin, productionPlugin2]


export default Object.assign(, base, isProduction === true ? productionConfig : developmentConfig)

这是我的主要应用 index.js 的样子:

import React from 'react'
import ReactDOM from 'react-dom'
import getRoutes from './config/routes'
import  createStore, applyMiddleware, compose, combineReducers  from 'redux'
import  Provider  from 'react-redux'
import  authUser, unauthUser, fetchingUserSuccess  from 'redux/modules/users'
import ReduxThunk from 'redux-thunk'
import  initAuth, formatUserInfo  from 'helpers/auth'
import * as reducers from 'redux/modules'

let reducer = combineReducers(reducers)
// const store = createStore(
//   reducer,
//   compose(applyMiddleware(ReduxThunk),
//    window.devToolsExtension ? window.devToolsExtension() : f => f))

function configureStore () 
  const store = createStore(
  reducer,
  compose(applyMiddleware(ReduxThunk),
   window.devToolsExtension ? window.devToolsExtension() : f => f))

  if (module.hot) 
    module.hot.accept('redux/modules', () => 
      store.replaceReducer(require('redux/modules').default)
    )
  
  return store


const store = configureStore()

export function checkAuth (nextState, replace) 
  // debugger
  // console.log('isAuthed from Main container mount')
  // const isAuthed = checkIfAuthed(store)
  const isAuthed = store.getState().users.isAuthed
  // const isAuthed = store.getState().isAuthed
  console.log('isAuthed from checkAuth method', isAuthed)
  const nextPathName = nextState.location.pathname
  console.log('nextPathName', nextPathName)
  // debugger
  if ((isAuthed !== true) && (nextPathName !== 'auth')) 
      // debugger
    console.log('replaced path to auth')
    replace('auth')
   else if ((nextPathName === '/' || nextPathName === 'auth') && (isAuthed === true)) 
      // debugger
    console.log('replaced path to feed')
    replace('feed')
  


initAuth()
.then((user) => 
  if (user !== null) 
    console.log('intial user', user.displayName)
    store.dispatch(authUser(user.uid))
    const userInfo = formatUserInfo(user.displayName, user.photoURL, user.uid)
    store.dispatch(fetchingUserSuccess(user.uid, userInfo))
   else 
    console.log('intial user is :', user)
    store.dispatch(unauthUser())
  

  ReactDOM.render(
  <Provider store = store>
    getRoutes(checkAuth)
  </Provider>,
  document.getElementById('app')
)
)
.catch((error) => 
  console.log('ERROR', error)
)

【问题讨论】:

【参考方案1】:

在你的 App index.js 中移除这个方法

if (module.hot) 
module.hot.accept('redux/modules', () => 
  store.replaceReducer(require('redux/modules').default)
)

【讨论】:

我最近刚刚添加了这个 sn-p 代码,因为有人告诉我它可以让它工作。它没有或没有你要求我删除的这个 sn-p。如果您注意到 configureStore 函数正上方,我有一个注释代码。我还通过注释 configureStore 函数并取消注释上面的代码来运行它,我只是使用 createStore 创建一个常量存储【参考方案2】:

即使我无法复制问题(欢迎使用 jsfiddle),更换后更新商店应该会有所帮助:

if (module.hot) 
  module.hot.accept('redux/modules', () => 
  store.replaceReducer(require('redux/modules').default)
  if (window.devToolsExtension) window.devToolsExtension.updateStore(store)
)

【讨论】:

【参考方案3】:

使用redux-persist 通过页面刷新操作和选项卡或浏览器关闭来保持应用程序状态。

【讨论】:

以上是关于为啥在 Redux-DevTools 中使用 Webpack HMR 插件时 App 状态会重置?的主要内容,如果未能解决你的问题,请参考以下文章

P06:Chrome插件 Redux-DevTools 用来调试Redux数据

Redux-DevTools安装

Angular NGRX - 为 Redux-Devtools 命名 store/app-instance

将 redux-devtools 传递给带有中间件的 redux 存储

当我禁用redux-devtools时,路由器导航需要很长时间。

redux-devtools 浏览器修改Store值