acdlite / redux-router

Redux bindings for React Router – keep your router state inside your Redux store
MIT License
2.3k stars 200 forks source link

Warning: setState(...): Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and #171

Closed motephyr closed 8 years ago

motephyr commented 8 years ago

I used react-router, it's setting more complex than redux-router, but all ok. After I used redux-router, but I see some error in my debug window.

Warning: setState(...): Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and

it should be fix or I use wrong way to do it?

motephyr commented 8 years ago

my configureStore.js:

import { createStore, applyMiddleware,combineReducers,compose } from 'redux';
import thunkMiddleware from 'redux-thunk';
// import promiseMiddleware from 'redux-promise-middleware';
import promiseMiddleware from '../middleware/promiseMiddleware'
import loggerMiddleware from 'redux-logger';
import * as reducers from '../reducers';
import { reduxReactRouter, routerStateReducer } from 'redux-router';
import { createHistory } from 'history';

const createStoreWithMiddleware = compose(
  applyMiddleware(thunkMiddleware,promiseMiddleware(),loggerMiddleware),
  reduxReactRouter({
    createHistory
  })

  )(createStore);

const rootReducer = combineReducers({
  router: routerStateReducer,
  ...reducers
});

export default function configureStore(initialState) {
  const store = createStoreWithMiddleware(rootReducer, initialState);

  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextRootReducer = require('../reducers');
      store.replaceReducer(nextRootReducer);
    });
  }

  return store;
}

my Root:


import "babel-core/polyfill";
import "whatwg-fetch" ;

window.Session = require("utils/session");

import {captureException} from "utils/airbraker";

import ReactDOM from 'react-dom';

import {Component, PropTypes} from 'react';
import {Router, RouteHandler, IndexRoute, Route, Redirect } from "react-router";
import { ReduxRouter } from 'redux-router';

// import { DevTools, DebugPanel, LogMonitor } from 'redux-devtools/lib/react';
import {Provider} from 'react-redux';
import configureStore from './store/configureStore';
const store = configureStore();

import HomePage from "./pages/HomePage";
import CategoryPage from "./pages/CategoryPage";
import StoreListPage from "./pages/StoreListPage";
import SearchPage from "./pages/SearchPage";

export default class Root extends Component {

  render() {
    const processENV = process.env.NODE_ENV || "development"
    return (
      <div>
        <Provider store={store} >
          <ReduxRouter>
            <Redirect from="/" to="/index" />
            <Route path="/index" component={HomePage} />
            <Route path="/categories/:id(/:feature_id)" component={CategoryPage} />
            <Route path="/stores/following" component={StoreListPage} />
            <Route path="/search(/:category)(/:query)" component={SearchPage} />

          </ReduxRouter>
        </Provider>
      </div>
    );
  }
}

$(document).ready(function () {

  if (!Parse.User.current()) {
    //TODO Better handling, maybe redirect to login page.
    document.location = "/";
  } else {

    // captureException(() => {
      ReactDOM.render(
        <Root />,
        document.getElementById('app')
      );
    // })();
  }
});

i guess that i use the same name state in different container(page). and in switch two page it will print this error?

My HomePage's:

@connect(state => ({
  products: state.model.products,
  channelsFeed: state.model.channelsFeed,
  selfLikedProductsIds: state.model.selfLikedProductsIds,
  featureLists: state.model.featureLists,
  channelsFeatured: state.model.channelsFeatured,

}), dispatch => ({
  homeActions: bindActionCreators({...ModelActions, ...HomeActions
  }, dispatch),

}))

My CategoryPage's:

@connect(state => ({
  categoryProducts: state.model.categoryProducts,
  selfLikedProductsIds: state.model.selfLikedProductsIds,
  categories: state.model.categories,
  channelsFeatured: state.model.channelsFeatured,
  products: state.model.products,
  channelsFeed: state.model.channelsFeed,
  location: state.router.location,
}), dispatch => ({
  categoryActions: bindActionCreators({...ModelActions, ...HomeActions
  }, dispatch),

}))

products, selfLikedProductsIds, channelsFeatured is Repeatd.

motephyr commented 8 years ago

ok, I don't know why. but I do dispatch action in constructor() originally, now I move in componentWillMount(). And the error disappear.

But When i just use react-router , I have no this problem.

(Forgive me that My English is not very well)

Scarysize commented 8 years ago

Dispatching an action will mutate your current state, which you should not do in the constructor (which is your getInitialState function with es6 classes). Also you should never mutate your state in the render() method, as it is rendering depending on your current state. Mutating the state in anyway will trigger a re-render (a call to the render() function)...you recognize the problem in this. Maybe invest in some reading time of the react documentation: https://facebook.github.io/react/docs/component-api.html

robtg4 commented 8 years ago

@Scarysize What about in this case? I'm not sure how to change things around but from referencing other similar projects in github, the implementation is very similar: https://github.com/tabalt/ReactNativeNews/issues/3

marcusjwhelan commented 7 years ago

Since this comes up as one of the top results. I am using react-router-redux. I was receiving this error because an I was reacting to an action in the render method and trying to route to another component.

I fixed this by checking for the change in componentWillUpdate instead of render.

tcchau commented 6 years ago

You will also get this warning if you try to dispatch from a stateless functional component, for the same reasons as stated above. The warning message itself is a bit inaccurate though, because technically in this case, you're not using a constructor per se.

byeage commented 4 years ago

use useEffect instead of componentWillUpdate if you use stateless functional component