不能在我现有的combineReducers

时间:2018-02-13 12:55:44

标签: react-redux-form

在反应锅炉板项目之后,我想使用react-redux-forms并查看'get started'指南,它说只使用combineForms。我试图解决这个问题好几个小时,文档没有多大帮助。希望有人能够告诉我这里发生的事情。

我的研究时间让我相信:

  1. 我错误地使用了combineForms
  2. ImmutableJS不能与react-redux-forms一起使用
  3. 以下是我的文件:

    configureStore.js:

    / **  *使用动态Reducer创建商店  * /

    import {createStore, applyMiddleware, compose} from 'redux';
    import {fromJS} from 'immutable';
    import {routerMiddleware} from 'react-router-redux';
    import createSagaMiddleware from 'redux-saga';
    import createReducer from './reducers';
    
    
    const sagaMiddleware = createSagaMiddleware();
    
    export default function configureStore(initialState = {}, history) {
      // Create the store with two middlewares
      // 1. sagaMiddleware: Makes redux-sagas work
      // 2. routerMiddleware: Syncs the location/URL path to the state
      const middlewares = [
        sagaMiddleware,
        routerMiddleware(history),
      ];
    
      const enhancers = [
        applyMiddleware(...middlewares),
      ];
    
      // If Redux DevTools Extension is installed use it, otherwise use Redux compose
      /* eslint-disable no-underscore-dangle */
      const composeEnhancers =
        process.env.NODE_ENV !== 'production' &&
        typeof window === 'object' &&
        window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
          ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
            // TODO Try to remove when `react-router-redux` is out of beta, LOCATION_CHANGE should not be fired more than once after hot reloading
            // Prevent recomputing reducers for `replaceReducer`
            shouldHotReload: false,
          })
          : compose;
      /* eslint-enable */
    
    
      const store = createStore(
        createReducer(),
        fromJS(initialState),
        composeEnhancers(...enhancers)
      );
    
      // Extensions
      store.runSaga = sagaMiddleware.run;
      store.injectedReducers = {}; // Reducer registry
      store.injectedSagas = {}; // Saga registry
    
      // Make reducers hot reloadable, see http://mxs.is/googmo
      /* istanbul ignore next */
      if (module.hot) {
        module.hot.accept('./reducers', () => {
          store.replaceReducer(createReducer(store.injectedReducers));
        });
      }
    
      return store;
    }
    

    reducer.js:

    import { combineReducers } from 'redux-immutable';
    import { fromJS } from 'immutable';
    import { LOCATION_CHANGE } from 'react-router-redux';
    import { createForms, combineForms } from 'react-redux-form/immutable';
    import languageProviderReducer from 'containers/LanguageProvider/reducer';
    
    /*
     * routeReducer
     *
     * The reducer merges route location changes into our immutable state.
     * The change is necessitated by moving to react-router-redux@4
     *
     */
    
    // Initial routing state
    const routeInitialState = fromJS({
      location: null,
    });
    
    /**
     * Merge route into the global application state
     */
    function routeReducer(state = routeInitialState, action) {
      switch (action.type) {
        /* istanbul ignore next */
        case LOCATION_CHANGE:
          return state.merge({
            location: action.payload,
          });
        default:
          return state;
      }
    }
    
    const initialUserState = fromJS({
      firstName: '',
      lastName: '',
    });
    
    
    /**
     * Creates the main reducer with the dynamically injected ones
     */
    export default function createReducer(injectedReducers) {
      return combineReducers({
        route: routeReducer,
        language: languageProviderReducer,
        forms: combineForms({
          user: initialUserState,
        }, 'forms'),
        ...injectedReducers,
      });
    }
    

    index.js:

    import React from 'react';
    import {
      Form,
      Control,
    } from 'react-redux-form';
    
    
    export default function App() {
      return (
        <UserForm />
      );
    }
    
    class UserForm extends React.Component {
      render() {
        return (
          <Form
            model="user"
            onSubmit={(user) => this.handleSubmit(user)}
          >
            <label>First name:</label>
            <Control.text model=".firstName" />
            <button type="submit">
              Finish registration!
            </button>
          </Form>
        );
      }
    }
    

    app.js:

    /**
     * app.js
     *
     * This is the entry file for the application, only setup and boilerplate
     * code.
     */
    
    // Needed for redux-saga es6 generator support
    import 'babel-polyfill';
    
    // Import all the third party stuff
    import React from 'react';
    import ReactDOM from 'react-dom';
    import { Provider } from 'react-redux';
    import { ConnectedRouter } from 'react-router-redux';
    import FontFaceObserver from 'fontfaceobserver';
    import createHistory from 'history/createBrowserHistory';
    import 'sanitize.css/sanitize.css';
    
    // Import root app
    import App from 'containers/App';
    
    // Import Language Provider
    import LanguageProvider from 'containers/LanguageProvider';
    
    // Load the favicon, the manifest.json file and the .htaccess file
    /* eslint-disable import/no-webpack-loader-syntax */
    import '!file-loader?name=[name].[ext]!./images/favicon.ico';
    import '!file-loader?name=[name].[ext]!./images/icon-72x72.png';
    import '!file-loader?name=[name].[ext]!./images/icon-96x96.png';
    import '!file-loader?name=[name].[ext]!./images/icon-120x120.png';
    import '!file-loader?name=[name].[ext]!./images/icon-128x128.png';
    import '!file-loader?name=[name].[ext]!./images/icon-144x144.png';
    import '!file-loader?name=[name].[ext]!./images/icon-152x152.png';
    import '!file-loader?name=[name].[ext]!./images/icon-167x167.png';
    import '!file-loader?name=[name].[ext]!./images/icon-180x180.png';
    import '!file-loader?name=[name].[ext]!./images/icon-192x192.png';
    import '!file-loader?name=[name].[ext]!./images/icon-384x384.png';
    import '!file-loader?name=[name].[ext]!./images/icon-512x512.png';
    import '!file-loader?name=[name].[ext]!./manifest.json';
    import 'file-loader?name=[name].[ext]!./.htaccess'; // eslint-disable-line import/extensions
    /* eslint-enable import/no-webpack-loader-syntax */
    
    import configureStore from './configureStore';
    
    // Import i18n messages
    import { translationMessages } from './i18n';
    
    // Import CSS reset and Global Styles
    import './global-styles';
    
    // Observe loading of Open Sans (to remove open sans, remove the <link> tag in
    // the index.html file and this observer)
    const openSansObserver = new FontFaceObserver('Open Sans', {});
    
    // When Open Sans is loaded, add a font-family using Open Sans to the body
    openSansObserver.load().then(() => {
      document.body.classList.add('fontLoaded');
    }, () => {
      document.body.classList.remove('fontLoaded');
    });
    
    // Create redux store with history
    const initialState = {};
    const history = createHistory();
    const store = configureStore(initialState, history);
    const MOUNT_NODE = document.getElementById('app');
    
    const render = (messages) => {
      ReactDOM.render(
        <Provider store={store}>
          <LanguageProvider messages={messages}>
            <ConnectedRouter history={history}>
              <App />
            </ConnectedRouter>
          </LanguageProvider>
        </Provider>,
        MOUNT_NODE
      );
    };
    
    if (module.hot) {
      // Hot reloadable React components and translation json files
      // modules.hot.accept does not accept dynamic dependencies,
      // have to be constants at compile-time
      module.hot.accept(['./i18n', 'containers/App'], () => {
        ReactDOM.unmountComponentAtNode(MOUNT_NODE);
        render(translationMessages);
      });
    }
    
    // Chunked polyfill for browsers without Intl support
    if (!window.Intl) {
      (new Promise((resolve) => {
        resolve(import('intl'));
      }))
        .then(() => Promise.all([
          import('intl/locale-data/jsonp/en.js'),
          import('intl/locale-data/jsonp/de.js'),
        ]))
        .then(() => render(translationMessages))
        .catch((err) => {
          throw err;
        });
    } else {
      render(translationMessages);
    }
    
    // Install ServiceWorker and AppCache in the end since
    // it's not most important operation and if main code fails,
    // we do not want it installed
    if (process.env.NODE_ENV === 'production') {
      require('offline-plugin/runtime').install(); // eslint-disable-line global-require
    }
    

    从react-boiler-plate克隆后,大部分代码几乎都没有被触及,只是将index.js更改为只有表格并修改了reducer.js。

    我可以从redux dev工具中看到我有表单键:

    redux state

    但是我收到的错误消息是该应用无法加载:

    app won't load

    提前感谢一百万!

1 个答案:

答案 0 :(得分:0)

终于弄明白了。因为我使用的是immutableJS,所以我只需要改变导入:

import { Form, Control } from 'react-redux-form';

为:

import { Form, Control } from 'react-redux-form/immutable';