首页 文章

如何使用redux对native asyncstorage做出反应?

提问于
浏览
2

我已经进行了登录和注销操作以及userReducer . 如何将asyncstorage与redux集成?我使用redux thunk作为中间件 .

我能够使用内部状态变量实现登录和注销,但我无法理解如何将其分解为action和reducer以及使用asyncstorage来存储accessToken .

原始代码:

_onLogin = () => {
    auth0.webAuth
      .authorize({
        scope: 'openid profile',
        audience: 'https://' + credentials.domain + '/userinfo'
      })
      .then(credentials => {
        this.setState({ accessToken: credentials.accessToken });
      })
      .catch(error => console.log(error));
  };

  _onLogout = () => {
    if (Platform.OS === 'android') {
      this.setState({ accessToken: null });
    } else {
      auth0.webAuth
        .clearSession({})
        .then(success => {
          this.setState({ accessToken: null });
        })
        .catch(error => console.log(error));
    }
  };

loginAction.js:

import { LOGIN_USER } from './types';
import Auth0 from 'react-native-auth0';

var credentials = require('./auth0-credentials');
const auth0 = new Auth0(credentials);

export const loginUser = () => dispatch => {
    auth0.webAuth
    .authorize({
      scope: 'openid profile',
      audience: 'https://' + credentials.domain + '/userinfo'
    })
    .then(credentials =>
        dispatch({
            type: LOGIN_USER,
            payload: credentials.accessToken
        })
    )
    .catch(error => console.log(error));
}

logoutAction.js:

import { LOGOUT_USER } from './types';
import Auth0 from 'react-native-auth0';

var credentials = require('./auth0-credentials');
const auth0 = new Auth0(credentials);

export const logoutUser = () => dispatch => {

        auth0.webAuth
          .clearSession({})
          .then(success => 
                dispatch({
                    type: LOGOUT_USER,
                    payload: null
                })
          )
          .catch(error => console.log(error));
}

userReducer.js:

import { LOGIN_USER, LOGOUT_USER } from '../actions/types';

const initialState = {
    accessToken: null
}

export default function (state = initialState, action) {
    switch (action.type) {

        case LOGIN_USER:

            _storeData = async () => {
                try {
                    await AsyncStorage.setItem('accessToken', action.payload);
                } catch (error) {
                    console.log(error)
                }
            }

            return {
               ...state,
               accessToken:action.payload
            };

        case LOGOUT_USER:

            _removeData = async (accessToken) => {
                try {
                    await AsyncStorage.removeItem(accessToken);
                } catch (error) {
                    console.log(error)
                }
            }    

            return {
                ...state,
                accessToken:action.payload
            };

        default:
            return state;
    }
}

我是redux的新手,所以我尝试将原始代码转换为actions和reducers,但我不确定我是否在userReducer.js中正确实现了asyncstorage?

2 回答

  • 1

    您可以方便地单独使用AsyncStorage OR redux来管理身份验证状态 . 取决于你感到满意 . 我会举两个例子 .

    对于AsyncStorage:假设您的身份验证密钥仅在2周内有效 . 您可以在用户登录时记下并节省时间 . 例如:

    //LoginScreen
    import { onSignIn } from '../actions/auth'; //I will describe the onSignInMethod below
    import axios from 'axios'; //lets use axios. You may use fetch too.
    
    
    export default class LoginScreen extends Component {
    
    
        //your code: state, static etc
        loginMethod = () => {
            const url = yourauthUrl;
            const payload = {
                email: this.state.email,
                password: this.state.password
            };
            axios.post(url, payload)
            .then((response) => {
                if (response.status == 200) {
                    const dateOfLastLogin = new Date().getTime().toString(); //take note of the time the user logs in.
                    AsyncStorage.setItem('dateOfLastLogin', dateOfLastLogin);
                }
            })
            .then(() => { 
                onSignIn() //onSignIn handles your sign in. See below.
                .then(() => this.props.navigation.navigate('AfterSignInPage'));
                })
                .catch(() => { // your callback if onSignIn Fails
                });
            })
            .catch((error) => { //your callback if axios fails
            });
        }
    
    }
    

    ../actions/auth.js

    import { AsyncStorage } from 'react-native';
    
    export const onSignIn = () => AsyncStorage.setItem('auth_key', 'true');
    //in LoginScreen we called this to set that a user has successfully logged in
    //why is true a string? -- Because Asyncstorage stores only strings
    
    export const onSignOut = () => AsyncStorage.multiRemove(['auth_key', 'dateOfLastLogin']);
    
    //now lets create a method that checks if the user is logged in anytime
    export const isSignedIn = () => {
        return new Promise((resolve, reject) => {
            AsyncStorage.multiGet(['auth_key', 'dateOfLastLogin'])
            .then((res) => {
                const userKey = res[0][1];
                const lastLoginDate = parseInt(res[1][1]);
                const today = new Date().getTime();
                const daysElapsed = Math.round(
                    (today - lastLoginDate) / 86400000
                    );
                if (userKey !== null && (daysElapsed < 14)) {
                    resolve(true);
                } else {
                    resolve(false);
                }
            })
            .catch((err) => reject(err));
        });
    };
    

    现在我们可以从任何组件 import { isSignedIn } from '../actions/auth'; 使用它,如下所示:

    isSignedIn()
        .then((res) => {
            if (res) { 
                // user is properly logged in and the login keys are valid and less than 14 days 
            }
        })
    

    ////////////////////////////////////////////////// //////////////////////////

    如果你想使用redux

    处理redux中的登录

    在你的 types.js

    //types.js
    export const LOGGED_IN = 'LOGGED_IN';
    

    在你的redux行动中

    //loginActions.js
    import {
        LOGGED_IN,
    } from './types';
    
    export function login() {
        let dateOfLastLogin = null;
        let isLoggedIn = 'false';
        AsyncStorage.multiGet(['auth_key', 'dateOfLastLogin'])
        .then((res) => {
            isLoggedIn = res[0][1];
            dateOfLastLogin = parseInt(res[1][1]);
        }); //note this works asynchronously so, this may not be a good approach
        return {
            type: LOGGED_IN,
            isLoggedIn, 
            dateOfLastLogin
        };
    }
    

    在您的loginReducer中

    //LoginReducer.js
    import {
        LOGGED_IN
    } from '../actions/types';
    
    
    const initialState = {
        userIsLoggedIn: false
    };
    
    export function loginReducer(state=initialState, action) {
        switch (action.type) {
    
            case LOGGED_IN:
    
                const userKey = action.isLoggedIn;
                const lastLoginDate = action.dateOfLastLogin;
                const today = new Date().getTime();
                const daysElapsed = Math.round(
                    (today - lastLoginDate) / 86400000
                    );
                let trulyLoggedIn = false;
                if (userKey !== null && (daysElapsed < 14)) {
                    trulyLoggedIn = true;
                } else { trulyLoggedIn = false }
                return {
                    userIsLoggedIn: trulyLoggedIn
                };
    
            default:
                return state;
        }
    }
    

    在你的 ./reducers/index.js

    //reducers index.js
    import { combineReducers } from 'redux';
    
    import { loginReducer } from './LoginReducers';
    
    const rootReducer = combineReducers({
        loggedIn: loginReducer
    });
    
    export default rootReducer;
    

    在您使用redux-thunk的商店中,applyMiddleWare . 让我们称之为configureStore.js

    //configureStore.js
    import { createStore, applyMiddleware } from 'redux';
    import thunk from 'redux-thunk';
    import rootReducer from '../reducers';
    
    export default function configureStore(initialState) {
        return createStore(
            rootReducer,
            initialState,
            applyMiddleware(thunk)
        );
    }
    

    在你的App.js中

    //App.js
    import { Provider } from 'react-redux';
    import configureStore from './src/store/configureStore'; //where you configured your store
    import { YourMainNavigator } from '../src/config/router'; //where your root navigator is
    
    const store = configureStore();
    export default class App extends Component<{}> {
        render() {
            return (
                <Provider store={store}>
                    <YourMainNavigator />
                </Provider>
            );
        }
    }
    

    您应该知道 auth.js 中不再需要isSignedIn方法 . 您的登录方法与LoginScreen中的上述方法保持一致 .

    现在您可以使用redux来检查登录状态,如下所示:

    import React, {Component} from 'react';
    import {connect} from 'react-redux';
    
    class MyComponent extends Component {
        someFunction() {
            if (this.props.loggedIn) {
                //do something
            }
        }
    }
    const mapStateToProps = (state) => {
        return {
            loggedIn: state.loggedIn.userIsLoggedIn
        };
    }
    
    
    export default connect(mapStateToProps)(MyComponent);
    

    应该有一种更好的方法来使用redux来管理登录 - 比我在这里概述的要好 . 我认为您也可以使用redux来管理您的登录状态,而无需使用AsyncStorage . 您需要做的只是在您的loginScreen中,如果登录函数返回response.status =='ok',您可以向redux发送一个记录用户的操作 . 在上面的示例中,使用asyncstorage您可能只需要使用redux检查用户是否已登录 .

  • 1

    为了坚持redux状态,我建议你redux-persist .

    Installation:

    npm i -S redux-persist
    

    Usage:

    首先,配置redux store

    // configureStore.js
    
    import { createStore } from 'redux'
    import { persistStore, persistReducer } from 'redux-persist'
    import storage from 'redux-persist/lib/storage' // defaults to localStorage for web and AsyncStorage for react-native
    
    import rootReducer from './reducers'
    
    const persistConfig = {
      key: 'root',
      storage,
    }
    
    const persistedReducer = persistReducer(persistConfig, rootReducer)
    
    export default () => {
      let store = createStore(persistedReducer)
      let persistor = persistStore(store)
      return { store, persistor }
    }
    

    然后,使用 PersistGate 包装根组件

    import { PersistGate } from 'redux-persist/integration/react'
    
    // ... normal setup, create store and persistor, import components etc.
    
    const App = () => {
      return (
        <Provider store={store}>
          <PersistGate loading={null} persistor={persistor}>
            <RootComponent />
          </PersistGate>
        </Provider>
      );
    };
    

相关问题