Как использовать реакцию нативного асинхронного хранилища с редуксом? - PullRequest
0 голосов
/ 16 сентября 2018

Я сделал действия входа и выхода и userReducer. Как я могу интегрировать асинхронное хранилище с редуксом? Я использую Redux Thunk в качестве промежуточного программного обеспечения.

Я могу реализовать вход и выход из системы, используя внутреннюю переменную состояния, но я не могу понять, как разбить его на действия и редукторы, а также использовать асинхронное хранилище для хранения 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, поэтому я попытался преобразовать исходный код в действия и редукторы, но я не уверен, правильно ли я реализовал asyncstorage в userReducer.js?

Ответы [ 2 ]

0 голосов
/ 16 сентября 2018

Вы можете удобно использовать только AsyncStorage ИЛИ 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';

В ваших действиях с избыточностью

//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
    };
}

В вашем логинеReducer

//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, примените MidWare.Давайте назовем его 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>
        );
    }
}

Вы должны знать, что вам больше не нужен метод isSignedIn в вашем auth.js Ваш метод входа остается прежнимкак описано выше в 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', вы можете отправить действие для переадресации, в которое входит пользователь. В приведенном выше примере с использованием asyncstorage вам может потребоваться толькоиспользуйте избыточность, чтобы проверить, вошел ли пользователь в систему.

0 голосов
/ 16 сентября 2018

Для сохранения избыточного состояния я рекомендую вам redux-persist .

Установка:

npm i -S redux-persist

Использование:

Сначала настройте хранилище примитивов

// 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>
  );
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...