React/Redux store state is not saved

≯℡__Kan透↙ 提交于 2020-01-01 15:57:33

问题


I use thunk middleware and pass initial state to React, but the problem is that React state is not saved when I visit other links.
After successfully logged in, it's supposed to render dashboard.
User must be redirected to dashboard(which is the root path, /) when he tries to go to /login page.

Should i use redux-router too?

I omitted some of code, but it almost looks like below.

init.js
I passed store to Provider

import { Provider } from 'react-redux';
import configureStore from './store/configureStore';

const store = configureStore();

function requireAuth(nextState, replace) {
  const isLoggedIn = store.getState().auth.isLoggedIn;
  if (!isLoggedIn) {
    replace({
      pathname: '/login',
      state: { nextPathname: nextState.location.pathname }
    });
  }
}

<Provider store={store}>
    <Router history={browserHistory}>
      <Route path='/' component={App} store={store}>
        <IndexRoute
          components={{
            main: MainServices,
            aside: Aside
          }}
          onEnter={requireAuth}
          />
        <Route
          path="login"
          components={{
            login: Login
          }}
          />
         ...
    </Router>
  </Provider>

configureStore.js

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers/index';
import initialState from './initialState';

const store = applyMiddleware(thunk)(createStore);

export default function () {
  return store(rootReducer, initialState);
}

initialState.js

var initialState = {
  auth: {
    isLoggedIn: false,
    isLoggingIn: false,
    response: null,
  },
};

export default initialState;

App.jsx Initial App's state passed down to React's props

import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import Dashboard from './Dashboard';
import Login from './Login';
import { browserHistory } from 'react-router';

class App extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div className='appWrapper height'>
        {
          this.props.auth.isLoggedIn ?
          <Dashboard {...this.props} /> : <Login {...this.props} />
        }
      </div>
    );
  }
}


let mapStateToProps = function(appState) {
  return {
    auth: appState.auth,
  };
};

let mapDispatchToProps = function(dispatch) {
  return {
    logoutRequest: function() {
      console.log("logoutRequest dispatched!");
    }
  }
};

export default connect(mapStateToProps, mapDispatchToProps)(App);

Login.jsx

export default class Login extends React.Component {
  constructor(props) {
    super(props);
    console.log(`componentWillMount in login`);
    if (this.props.auth.isLoggedIn) {
      console.log(`you already logged in..!`);
      browserHistory.push('/');
    }
  }
  render() {
    return (
      <div className="login-outer">
        <Grid className="login-inner">
          <Row>
            <Col xs={12}>
              <LoginHeader />
              <LoginContainer />
            </Col>
          </Row>
        </Grid>
      </div>
    );
  }
}

LoginContainer.jsx

export default class LoginContainer extends React.Component {
  render() {
    return (
      <div className="login-container">
        <div className="outer">
          <div className="inner">
            <LoginTitle />
            <div className="login-box">
              <h2>Sign in</h2>
              <LoginInput />
            </div>
          </div>
        </div>
      </div>
    );
  }
}

LoginInput.jsx

import React from 'react';
import { connect } from 'react-redux';
import { Input, ButtonToolbar, Button } from 'react-bootstrap';
import { spring } from 'react-motion';
import Transition from 'react-motion-ui-pack';
import Loader from 'react-loader';
import * as actions from '../../actions/loginActions';

class LoginInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      idText: '',
      passText: '',
      idShow: false,
      passShow: false,
      loaded: true
    };

    this.handleIdChange = this.handleIdChange.bind(this);
    this.handlePassChange = this.handlePassChange.bind(this);
    this.loginRequest = this.loginRequest.bind(this);
  }

  handleIdChange(e) {
    this.setState({
      idText: e.target.value
    });

    if (e.target.value != '') {
      this.setState({
        idShow: true
      });
    } else {
      this.setState({
        idShow: false
      });
    }
  }

  handlePassChange(e) {
    this.setState({
      passText: e.target.value
    });

    if (e.target.value != '') {
      this.setState({
        passShow: true
      });
    } else {
      this.setState({
        passShow: false
      });
    }
  }

  loginRequest(e) {

    this.setState({loaded: false});

    if (!this.state.idText || !this.state.passText) {
      this.setState({loaded: true});
    }

    if (this.state.idText && this.state.passText) {
      this.setState({
        loaded: false,
        idText: this.state.idText,
        passText: this.state.passText,
      });
      this.props.login(this.state.idText, this.state.passText);
    }

    e.preventDefault();
  }

   render() {
    return (
      <form className="loginForm">
        <div className="form-group input-login id">
            <input
              type="text"
              className="form-control"
              ref="idText"
              placeholder="ID"
              value={this.state.idText}
              onChange={this.handleIdChange}
            />
          <Transition
            component={false}
            enter={{
              opacity: 1
            }}
            leave={{
              opacity: 0
            }}
          >
            {
              this.state.idShow &&
              <label
                htmlFor=""
                className="control-label"
              >
                ID
              </label>
            }
          </Transition>
        </div>
        <div className="form-group input-login password">
          <input
            type="password"
            className="form-control"
            ref="passText"
            placeholder="Password"
            value={this.state.passText}
            onChange={this.handlePassChange}
          />
          <Transition
            component={false}
            enter={{
              opacity: 1
            }}
            leave={{
              opacity: 0
            }}
          >
            {
              this.state.passShow &&
              <label
                htmlFor=""
                className="control-label"
              >
                Password
              </label>
            }
          </Transition>
        </div>
        <Input
          type="checkbox"
          groupClassName="checkbox-login"
          label="Keep me signed in"
        />
        <ButtonToolbar>
          <Button
            href="#"
            onClick={this.loginRequest}
          >
            <div
              className="sign-arrow"
              hidden={!this.state.loaded}
            >
              <h6>
                ENTER
              </h6>
              <img src="images/ic-right-arrow-2.svg" alt="" />
            </div>
            <Loader
              className="spinner"
              loaded={this.state.loaded}
              lines={10}
              length={3}
              width={2}
              radius={4}
              corners={1}
              rotate={0}
              direction={1}
              color="#fff"
              speed={1.5}
              trail={60}
              shadow={false}
              hwaccel={false}
              scale={1}
            />
          </Button>
        </ButtonToolbar>
      </form>
    );
  }
}

let mapStateToProps = function(appState) {
  return {
    auth: appState.auth,
  };
};

let mapDispatchToProps = function(dispatch) {
  return {
          login: function(id, pwd) {
            dispatch(actions.login(id, pwd));
          }
  }
};

export default connect(mapStateToProps,mapDispatchToProps)(LoginInput);

loginActions.js

export function loginFailure(error) {
  return { error, type: ActionTypes.LOGIN_FAILURE };
}

export function loginSuccess(response) {
  return dispatch => {
    dispatch({ response, type: ActionTypes.LOGIN_SUCCESS });
    browserHistory.push('/');
  };
}

export function loginRequest(id, pwd) {
  return {
    type: ActionTypes.LOGIN_REQUEST,
    command: 'login',
    lang: 'en',
    str: encodeCredentials(id, pwd),
    ip: '',
    device_id: '',
    install_ver: '',
  };
}

export function login(id, pwd) {
  const credentials = loginRequest(id, pwd);

  return dispatch => {
    fetchJSON(`${API.ROOT_PATH}${API.END_POINT.LOGIN}`, {
      method: 'post',
      body: credentials,
    }).then(data => {
      dispatch(loginSuccess(data));
    }).catch(error => {
      console.log(`request failed ${error}`);
    });
  };

}

reducers/index.js

import authReducer from './authReducer';
import { combineReducers } from 'redux';

const rootReducer = combineReducers({
  auth: authReducer,
});

export default rootReducer;

authReducer.js

import initialState from '../store/initialState';
import * as ActionTypes from '../actionTypes/authActionTypes';

const authReducer = function authReducer(state = initialState.auth, action) {
  switch (action.type) {
    case ActionTypes.LOGIN_REQUEST:
      return Object.assign({}, state, {
        isLoggingIn: true,
        isLoggedIn: false,
      });
    case ActionTypes.LOGOUT:
      return Object.assign({}, state, {
        isLoggedIn: false,
        isLoggingIn: false,
      });
    case ActionTypes.LOGIN_FAILURE:
      return Object.assign({}, state, {
        error: action.error,
        isLoggingIn: false,
        isLoggedIn: false,
      });
    case ActionTypes.LOGIN_SUCCESS:
      return Object.assign({}, state, {
        isLoggedIn: true,
        isLoggingIn: false,
        response: action.response,
      });
    default:
      return state;
  }
};

export default authReducer;

回答1:


There is no way how your store can be saved between two different http requests. The only approach for that is not reloading page itself, but you can emulate for user that page was reloaded when user clicks the link by manipulation with history API which is native object in all modern browsers. BUT best approach is to take react-router which will take care about everything you need in your react App, and if you want to keep state of the router in your redux store you can use redux-simple-router.



来源:https://stackoverflow.com/questions/34810471/react-redux-store-state-is-not-saved

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!