簡體   English   中英

重定向后的React-Router-Redux setState警告

[英]React-router-redux setState warning after redirect

我正在為一個帶有React,redux, react-routerreact-router-redux的項目構建管理應用程序。 v4.0.0 -router是v4.0.0 ,react-router-redux是v5.0.0-alpha.3 (與npm install react-router-redux@next一起npm install react-router-redux@next )。 我正在嘗試的是:

  1. 加載應用,
  2. 執行異步調用到后端,以查看用戶是否已登錄(令牌存儲在Cookie中),
  3. 如果用戶未登錄,請重定向到/login並呈現“ Login組件。

對於異步操作,我正在使用redux-thunk

Root.js

import React, { Component, PropTypes } from 'react';
import { Provider, connect } from 'react-redux';
import { Route, Switch } from 'react-router-dom';
import { ConnectedRouter, push } from 'react-router-redux';

import Login from './Login';

const App = () => <h1>Dashboard</h1>;
const NotFound = () => <h1>Not found :(</h1>;

class Root extends Component {

  // use componentDidMount as recommended here:
  // https://facebook.github.io/react/docs/react-component.html#componentdidmount
  componentDidMount() {
    const { dispatch, user } = this.props;
    if (!user) {
      dispatch(push('/login'));
    }
  }

  render() {
    const { store, history } = this.props;
    return (
      <Provider store={store}>
        <ConnectedRouter history={history}>
          <div>
            <Switch>
              <Route exact path='/' component={App} />
              <Route exact path='/login' component={Login} />
              <Route component={NotFound} />
            </Switch>
          </div>
        </ConnectedRouter>
      </Provider>
    );
  }
}

Root.propTypes = {
  store: PropTypes.object.isRequired,
  history: PropTypes.object.isRequired,
  dispatch: PropTypes.func.isRequired,
  user: PropTypes.shape({
    email: PropTypes.string.isRequired
  })
};

const mapStateToProps = state => ({
  ready: state.ready,
  user: state.user
});

export default connect(mapStateToProps)(Root);

Login.js

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';

import {
  loginFormChange,
  loginFormSubmit
} from '../actions';

class Login extends Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    const { target } = event,
      { value, name } =  target,
      { dispatch } = this.props;
    dispatch(loginFormChange({
      [name]: value
    }));
  }

  handleSubmit(event) {
    event.preventDefault();
    const { dispatch, login } = this.props,
      { email, password } =  login;
    dispatch(loginFormSubmit({
      email,
      password
    }));
  }

  render() {
    const { login } = this.props,
      { email, password } = login;
    return (
      <form onSubmit={this.handleSubmit}>
        <input type="email" name="email" value={email} onChange={this.handleChange} />
        <input type="password" name="password" value={password} onChange={this.handleChange} />
        <button type="submit">Sign in</button>
      </form>
    );
  }
}

Login.propTypes = {
  dispatch: PropTypes.func.isRequired,
  login: PropTypes.shape({
    email: PropTypes.string.isRequired,
    password: PropTypes.string.isRequired
  }).isRequired
};

const mapStateToProps = state => ({
  login: state.login
});

export default connect(mapStateToProps)(Login);

actions.js

export const LOGIN_FORM_CHANGE = 'Login form change';
export const LOGIN_FORM_SUBMIT = 'Login form submit';
export const AUTHENTICATE_USER = 'Authenticate user';

export const loginFormChange = data => {
  const { email, password } = data;
  return {
    type: LOGIN_FORM_CHANGE,
    email,
    password
  };
};

export const loginFormSubmit = data => dispatch => {
  const { email, password } = data;
  return fetch('/api/auth/token', {
    headers: {
      'Authorization': 'Basic ' + btoa([ email, password ].join(':'))
    },
    credentials: 'same-origin'
  })
    .then(response => {
      if (!response.ok) {
        throw new Error(response.statusText);
      }
      return response.json();
    })
    .then(user => {
      // this line will throw setState warning:
      // Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.
      dispatch(authenticateUser(user));
    });
};

export const authenticateUser = data => {
  const { email } = data;
  return {
    type: AUTHENTICATE_USER,
    email
  };
};

我想指出的是,我正在使用推薦的異步操作方法,如redux文檔中所述 為了簡潔起見,我不會發布減速器。 最后:

index.js

import React from 'react';
import { render } from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import createHistory from 'history/createBrowserHistory';
import { routerMiddleware } from 'react-router-redux';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';

import reducers from './reducers';
import Root from './containers/Root';

const history = createHistory(),
  middleware = [
    routerMiddleware(history),
    thunk
  ];

if (process.env.NODE_ENV !== 'production') {
  middleware.push(createLogger());
}

const store = createStore(
  reducers,
  applyMiddleware(...middleware)
);

render(
  <Root store={store} history={history} />,
  document.getElementsById('root')
);

因此,當嘗試分發同步 authenticateUser操作時,該警告會引發在loginFormSubmit異步操作中。 此外,它僅在重定向后發生。 我嘗試了不同的重定向方法:

  • 從react-router-redux push
  • 從react-router Redirect組件

我還嘗試了將重定向調用放在不同的位置( componentWillMountcomponentDidMountcomponentWillReceiveProps ,在組件內部進行條件渲染,使用react-router文檔中描述的條件PrivateRoute組件等),但似乎沒有任何效果。

如果首先沒有重定向(例如,用戶打開/login頁面而不是受保護的頁面),則沒有警告。

非常感謝您對此問題的任何幫助。

我有相同的問題,基本上這是來自react-router-redux v5.0.0-alpha.2和alpha.3的ConnectedRouter的錯誤

過去幾天一直在積極討論該問題,但現在已在alpha 4中修復,並且此問題已解決:

https://github.com/ReactTraining/react-router/issues/4713

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM