Reactjs,Redux - redux-persist

时间:2017-09-13 23:25:32

标签: reactjs redux react-redux

我正在研究reactjs / redux应用程序 - 并使用Java Spring Boot代码库充当api。

我有一个登录系统 - 但我注意到当我刷新页面时 - 身份验证状态丢失了。

我添加了redux-persist,但它似乎没有对存储登录状态和恢复体验产生任何影响?

我的router.js上有大量的redux-persist,它就是商店/提供商设置到应用程序的地方。

我不确定用户登录时如何以及在何处存储状态 - 我已经公开了登录表单,你可以看到我开始检查this.props.authData状态 - 它会在哪里理想的是调用persistor.rehydrate() - 但是那时我无法访问这些页面上的persistor或store?

// router.js

import React, { Component } from 'react'
import { BrowserRouter as Router, Route, Redirect, Switch } from 'react-router-dom'
import createBrowserHistory from 'history/createBrowserHistory'
import { Provider } from 'react-redux'
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk';
import {persistStore, autoRehydrate} from 'redux-persist'

import rootReducer from './reducers/rootReducer'

// components
import Login from './components/Login/Login'
import ForgotPassword from './components/ForgotPassword/ForgotPassword'
import RegisterUser from './components/RegisterUser/RegisterUser'

import Home from './components/Home/Home'
import Actions from './components/Actions/Actions'
import AddSDQ from './components/Actions/AddSDQ'

import PastSDQ from './components/PastSDQ/PastSDQ'
import Account from './components/Account/Account'

import Logout from './components/Logout/Logout'

import About from './components/About/About'
import Terms from './components/Terms/Terms'
import Privacy from './components/Privacy/Privacy'

import Error from './components/Error/Error'

import Header from './components/Header/Header'
import Footer from './components/Footer/Footer'

const history = createBrowserHistory()

// add `autoRehydrate` as an enhancer to your store (note: `autoRehydrate` is not a middleware)
const store = createStore(
    rootReducer,
    applyMiddleware(thunk),
    autoRehydrate()
);

const persistor = persistStore(store, {}, () => {
  console.log('restored');
})

// we can pass the lang files as props to the routes
// we should have a nested route inside service here to show the other services page

class Routes extends Component {

  constructor (props) {
    super(props)

    /*
    this.state = {
      rehydrated: false
    }*/
    //console.log("router level", this.props)
    //console.log("state-->", this.state)
  }

  componentWillMount(){
    // begin periodically persisting the store
    /*
    persistStore(store, {}, () => {
      this.setState({ rehydrated: true })
      console.log("rehydrated", store);
    })*/
  }

  render () {

    console.log("this props", this);

    // when the user has logged in - navigate them to the home page
    if(this.props.authData){
        //this.props.authData.isLogged
      //return <Redirect to='/home'/>;
      console.log("user logged!!!!!!!!!!!");
      //persistor.rehydrate()//calls reducer to rehydrate store
    } 


    const loggedIn = true;//this.state.isLoggedIn;
    console.log("rendered store", store);

    return (
      <Provider store={store}>
        <Router history={history}>
          <div className='off-canvas-wrap' data-offcanvas>
            <div className='inner-wrap'>
              <Header transparent />
              <Switch>
                <Route path='/home' component={Home} />
                <Route path='/past-sdq' component={PastSDQ} />
                <Route path='/actions' component={Actions} />
                <Route path='/add-sdq' component={AddSDQ} />

                <Route path='/account' component={Account} />

                <Route path='/about' component={About} />
                <Route path='/terms' component={Terms} />
                <Route path='/privacy' component={Privacy} />

                <Route path='/login' component={Login} />
                <Route path='/logout' component={Logout} />
                <Route path='/forgot-password' component={ForgotPassword} />
                <Route path='/register-user' component={RegisterUser} />

                {/*<Route path='/api/:serviceRequest' />*/}

                <Route exact path="/" render={() => ( loggedIn ? ( <Home/> ) : ( <Redirect to="/login"/> ) )} />

                <Route component={Error} />
              </Switch>
              <Footer transparent />
            </div>
          </div>
        </Router>
      </Provider>
    )
  }
}

export default Routes

// rootReducer.js

import { combineReducers } from 'redux'
import { reducer as formReducer } from 'redux-form'

import { authReducer } from './authReducer'
import { regReducer } from './regReducer'
import { forgotReducer } from './forgotReducer'
import { homeReducer } from './homeReducer'
import { editProfileReducer } from './editProfileReducer'
import { initProfileReducer } from './initProfileReducer'
import { editFollowUpReducer } from './editFollowUpReducer'
import { initFollowUpReducer } from './initFollowUpReducer'
import { addSDQReducer } from './addSDQReducer'
import { pastSDQReducer } from './pastSDQReducer'

import { rehydrateReducer } from './rehydrateReducer'


const rootReducer = combineReducers({
  form: formReducer,
  auth: authReducer,
  reg: regReducer,
  forgot: forgotReducer,
  home: homeReducer,
  editProfile: editProfileReducer,
  initProfile: initProfileReducer,
  editFollowUp: editFollowUpReducer,
  initFollowUp: initFollowUpReducer,
  addSDQ: addSDQReducer,
  pastSDQ: pastSDQReducer,
  rehydrate: rehydrateReducer
})

export default rootReducer

// rehydrateReducer.js

import {REHYDRATE} from 'redux-persist/constants'

export function rehydrateReducer (state = {}, action) {
  //console.log('reducer REHYDRATE act', action)
  switch (action.type) {
    case REHYDRATE:
      return {...state, data: action.payload};
    default:
      return {...state} 
  }
} 

// login.js

import React, { Component } from 'react'
import { withRouter, Redirect } from 'react-router-dom';
//import { withRouter, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchAuthentication } from '../../actions/authAction';

import {persistStore} from 'redux-persist'

import { Row, Col } from 'antd';

// components
import LoginSyncValidationForm from './LoginSyncValidationForm'

import '../../forms.scss';


// this is a class because it needs state
class Login extends Component {

  constructor(props, context) {
    super(props, context);
    this.submit = this.submit.bind(this);
  }

  /*
  static propTypes = {
    isDark: React.PropTypes.bool
  }
  static defaultProps = {
    isDark: false
  }
  */

  componentDidMount() {
    //document.body.classList.toggle('darkClass', this.props.isDark)
  }
  componentWillReceiveProps(nextProps) {
    //document.body.classList.toggle('darkClass', nextProps.isDark)
  }

  componentWillMount () {
    document.body.classList.add('screenbackground');
  }

  componentWillUnmount() {
    document.body.classList.remove('screenbackground');
  }

  submit(data) {
    this.props.fetchAuthentication(data);
  }

  render() {

    var errorPlaceholder = "";

    //console.log("authss-->", this.props.authData);
    if(this.props.authData.data){

      //console.log("status--<", this.props.authData.data.data.status);
      //if error from server side show the message
      if(this.props.authData.data.data.status !== "success"){
        errorPlaceholder = this.props.authData.data.data.msg;
      }
    }


    // when the user has logged in - navigate them to the home page
    if(this.props.authData.isLogged){
      //return <Redirect to='/home'/>;

      //persistor.rehydrate()//calls reducer to rehydrate store
    } 

    return (
      <div className="Page form-components light">
        <h2>Login</h2>
        <Row>
          <Col xs={24} sm={24} md={10}>
            <p>Welcome to the SLAM SDQ tracker. Because you are accessing sensitive info, you need to verify your identity using our secure login system. This will not only protect your data, but will provide a platform where you can be in control of your progress. Your unique identification number has been sent to you by e-mail. Use it to login. If you have not created an account yet or have forgotten your password, please use the links below to complete the desired action.</p>
          </Col>
          <Col xs={24} sm={24} md={24}>
            <Row>
              <Col xs={24} sm={24} md={6}>
                <LoginSyncValidationForm onSubmit={this.submit} />
              </Col>
            </Row>
          </Col>
          {errorPlaceholder.length > 0 &&
            <Col xs={24} sm={24} md={24}>
              {errorPlaceholder}
            </Col>
          }
        </Row>
        <div className="shell" />
        <div className="screen-background login"/>
      </div>
    )
  }

}

function mapStateToProps(state) {
  return {
    authData: state.auth
  };
}

function mapDispatchToProps(dispatch) {
 return bindActionCreators({ fetchAuthentication }, dispatch);
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Login))

更新1:14/09/2017

这是我的authAction.js的样子

// authAction.js

    import axios from 'axios';

    export const FETCH_AUTH_SUCCESS = 'FETCH_AUTH_SUCCESS'
    export const FETCH_AUTH_FAILURE = 'FETCH_AUTH_FAILURE'
    export const FETCH_AUTH_CLEAR = 'FETCH_AUTH_CLEAR'

    export function authSuccess(response) {
      return {
        type: FETCH_AUTH_SUCCESS,
        payload: response
      }
    }

    export function authFail(response) {
      return {
        type: FETCH_AUTH_FAILURE,
        payload: response
      }
    }

export function authClear() {
  return {
    type: FETCH_AUTH_CLEAR,
    payload: null
  }
}


export function fetchAuthentication(data) {

  let url = 'http://localhost:8080/login';

  return function (dispatch) {     
     //axios.post(url, data)
   axios.get(url, {
      params: data
    })
      .then(function (response) {
        console.log(response);

      if(response.data.status === "success"){
        dispatch(authSuccess(response));
      }
      else{
        // fail - user not found for example
        dispatch(authFail(response));
      }

      })
      .catch(function (error) {
        //console.log(error);
        dispatch(authFail(error));
      });
  }
}


export function clearAuthentication() {

  let url = 'http://localhost:8080/logout';

  return function (dispatch) {     
   //axios.post(url, data)
   axios.get(url)
    .then(function (response) {
      console.log(response);

      if(response.data.status === "success"){
        dispatch(authClear(response));
      }
      else{
        // fail - user not found for example
        dispatch(authFail(response));
      }

    })
    .catch(function (error) {
      //console.log(error);
      dispatch(authFail(error));
    });
  }
}

// authReducer.js

import { FETCH_AUTH_SUCCESS, FETCH_AUTH_FAILURE, FETCH_AUTH_CLEAR } from '../actions/authAction'

export function authReducer (state = {}, action) {
  //console.log('reducer act', action)
  switch (action.type) {
    case FETCH_AUTH_SUCCESS:
      return {...state, data: action.payload, isLogged: true};
    case FETCH_AUTH_FAILURE:
      return {...state, data: action.payload, isLogged: false}; 
    case FETCH_AUTH_CLEAR:
      return {...state, data: action.payload, isLogged: false};
    default:
      return {...state} 
  }
}

根据“Steven Daniel Anderson”的回答

const user = localStorage.getItem('user')
if(user){
    //Set the state authenticated to true;
    store.dispatch({
        type:AUTH_USER
    })
}

更像是

const user = localStorage.getItem('user')
if(user){
    //Set the state authenticated to true;
    authSuccess(user)
}

或在我的操作中创建一个像这样的新功能

export function fetchResumeAuth(data) {
   dispatch(authSuccess(data));
}

然后在用户检查 - 这将放在router.js?

const user = localStorage.getItem('user')
if(user){
    //Set the state authenticated to true;
    fetchResumeAuth(user)
}

1 个答案:

答案 0 :(得分:0)

您可以使用localStorage在浏览器中保存用户:

您在操作创建者中的

localStorage.setItem('user',user)用于登录。

然后创建一个reducer,如果用户通过身份验证,则将状态设置为true,如果不是,则设置为false,如下所示:

import { AUTH_USER, UNAUTH_USER, ERROR } from '../actions/types'

export default function (state={}, action){
    switch(action.type){
        case AUTH_USER:
            return { ...state, authenticated: true }
        case UNAUTH_USER:
            return { ...state, authenticated: false }
        default:
            return state
    }

}

如果用户在每次重新加载页面时都经过身份验证,则会在index.js文件中验证最后一部分:

const user = localStorage.getItem('user')
if(user){
    //Set the state authenticated to true;
    store.dispatch({
        type:AUTH_USER
    })
}

注意:您可以在任何视图中使用localStorage.getItem('user')来访问用户。