ReplaceReducer causing unexpected key error

前端 未结 1 1022
名媛妹妹
名媛妹妹 2021-02-08 19:10

I have a React app that dynamically loads a module, including the module\'s reducer function, and then calls Redux\'s replaceReducer to, well, replace the reducer. Unfortunatel

相关标签:
1条回答
  • 2021-02-08 19:54

    In general we don’t suggest you to “clean up” the data when changing routes or loading new modules. This makes the application a little less predictable. If we’re talking about hundreds of thousands of records, then sure. Is this the volume of the data you plan to load?

    If there’s just a couple of thousands of items on every page, there is no benefit to unloading them, and there are downsides associated with the complexity you add to the application. So make sure you’re solving a real problem, and not optimizing prematurely.

    Now, to the warning message. The check is defined inside combineReducers(). It means that unexpected state keys will be discarded. After you removed the bookEntry reducer that managed state.bookEntry, that part of the state was no longer recognized by the new root reducer, and combineReducers() logged a warning that it’s going to be discarded. Note that this is a warning, and not an error. Your code runs just fine. We use console.error() to make warning prominent, but it didn’t actually throw, so you can safely ignore it.

    We don’t really want to make the warning configurable because you’re essentially implicitly deleting part of the application state. Usually people do this by mistake, and not intentionally. So we want to warn about that. If you want to get around the warning, your best bet is to write the root reducer (currently generated by combineReducers()) by hand. It would look like this:

    // I renamed what you called "root" reducer
    // to "main" reducer because the root reducer
    // is the combined one.
    let mainReducer = (state, action) => ...
    
    // This is like your own combineReducers() with custom behavior
    function getRootReducer(dynamicReducer) {
      // Creates a reducer from the main and a dynamic reducer
      return function (state, action) {
        // Calculate main state
        let nextState = {
          main: mainReducer(state.main, action)
        };
    
        // If specified, calculate dynamic reducer state
        if (dynamicReducer) {
          nextState[dynamicReducer.name] = dynamicReducer.reducer(
            nextState[dynamicReducer.name],
            action
          );
        }
    
        return nextState;
      };
    }
    
    // Create the store without a dynamic reducer
    export function createStoreWithoutDynamicReducer() {
      return Redux.createStore(getRootReducer());
    }
    
    // Later call this to replace the dynamic reducer on a store instance
    export function setDynamicReducer(store, dynamicReducer) {
      store.replaceReducer(getRootReducer(dynamicReducer));
    }
    

    However the pattern we recommend is to keep the old reducers around.

    0 讨论(0)
提交回复
热议问题