不保存React / Redux存储状态 [英] React/Redux store state is not saved

查看:100
本文介绍了不保存React / Redux存储状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用thunk中间件并将初始状态传递给React,但问题是当我访问其他链接时没有保存React状态。

成功登录后,它应该呈现仪表板。 >
当用户尝试转到 / login / ) c $ c>页面。

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.

我是否也应该使用redux-router?

Should i use redux-router too?

我省略了一些代码,但它几乎如下所示。

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

init.js

我将商店传递给提供商

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
初始应用程序的状态通过到React的道具

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;


推荐答案

您的商店无法如何保存两个不同的http请求。唯一的方法是不重新加载页面本身,但是当用户通过使用历史API(在所有现代浏览器中是本机对象)进行操作来点击链接时,您可以模拟用户该页面被重新加载。但最好的方法是采用 react-router ,这将在您的反应应用程序中处理您需要的一切,如果您想在redux商店中保留路由器的状态,可以使用 redux-simple-router

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.

这篇关于不保存React / Redux存储状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆