Как преобразовать код localStorage в React в AsyncStorage в React Native?

Я хочу знать, как преобразовать мой код React в React Native с помощью AsyncStorage. Я пробовал приведенный ниже код, но получаю неопределенное значение для isAuthenticated, а также ошибку в JSON.parse(AsyncStorage.getItem('token'). Я хочу использовать значение isAuthenticated, чтобы показать только определенную часть компонента.

Код реакции:

export const Auth = (state = {
        isLoading: false,
        isAuthenticated: localStorage.getItem('token') ? true : false,
        token: localStorage.getItem('token'),
        user: localStorage.getItem('creds') ? JSON.parse(localStorage.getItem('creds')) : null,
        errMess: null
    }, action) => {
    switch (action.type) {
        case ActionTypes.LOGIN_REQUEST:
            return {...state,
                isLoading: true,
                isAuthenticated: false,
                user: action.creds
            };
        case ActionTypes.LOGIN_SUCCESS:
            return {...state,
                isLoading: false,
                isAuthenticated: true,
                errMess: '',
                token: action.token
            };
        case ActionTypes.LOGIN_FAILURE:
            return {...state,
                isLoading: false,
                isAuthenticated: false,
                errMess: action.message
            };
        case ActionTypes.LOGOUT_REQUEST:
            return {...state,
                isLoading: true,
                isAuthenticated: true
            };
        case ActionTypes.LOGOUT_SUCCESS:
            return {...state,
                isLoading: false,
                isAuthenticated: false,
                token: '',
                user: null
            };
        default:
            return state
    }
}

Мой код в React Native:

import * as ActionTypes from './ActionTypes';

// The auth reducer. The starting state sets authentication
// based on a token being in local storage. In a real app,
// we would also want a util to check if the token is expired.
export const auth = (state = {
  isLoading: false,
  isAuthenticated: false,
  token: null,
  user: null,
  errMess: null
}, action) => {
  switch (action.type) {
    case ActionTypes.GET_AUTH:
      return {
        ...state,
        ...action.payload
      };
    case ActionTypes.LOGIN_REQUEST:
      return {
        ...state,
        isLoading: true,
        isAuthenticated: false,
        user: action.creds
      };
    case ActionTypes.LOGIN_SUCCESS:
      return {
        ...state,
        isLoading: false,
        isAuthenticated: true,
        errMess: '',
        token: action.token
      };
    case ActionTypes.LOGIN_FAILURE:
      return {
        ...state,
        isLoading: false,
        isAuthenticated: false,
        errMess: action.message
      };
    case ActionTypes.LOGOUT_REQUEST:
      return {
        ...state,
        isLoading: true,
        isAuthenticated: true
      };
    case ActionTypes.LOGOUT_SUCCESS:
      return {
        ...state,
        isLoading: false,
        isAuthenticated: false,
        token: '',
        user: null
      };
    default:
      return state
  }
}

Заранее спасибо.

Изменить: это мой обновленный код.

export const getAuth = () => {
  return async(dispatch) => {
    const [token, creds] = await Promise.all([
      AsyncStorage.getItem('token'),
      AsyncStorage.getItem('creds')
    ])

    dispatch({
      type: ActionTypes.GET_AUTH,
      payload: {
        isLoading: false,
        isAuthenticated: !!token,
        token: token,
        user: JSON.parse(creds),
        errMess: null
      }
    });
  }
}

export const loginUser = (creds) => (dispatch) => {
  // We dispatch requestLogin to kickoff the call to the API
  dispatch(requestLogin(creds))

  return fetch(baseUrl + 'users/login', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(creds)
    })
    .then(response => {
        if (response.ok) {
          return response;
        } else {
          var error = new Error('Error ' + response.status + ': ' + response.statusText);
          error.response = response;
          throw error;
        }
      },
      error => {
        throw error;
      })
    .then(response => response.json())
    .then(response => {
      if (response.success) {
        async() => {
          try {
            await AsyncStorage.setItem('token', response.token);
            await AsyncStorage.setItem('creds', JSON.stringify(creds));
          } catch (error) {
            // Error saving data
          }
        }
        // If login was successful, set the token in local storage
        //AsyncStorage.setItem('token', response.token);
        //AsyncStorage.setItem('creds', JSON.stringify(creds));
        // Dispatch the success action
        dispatch(fetchSaves());
        dispatch(receiveLogin(response));
      } else {
        var error = new Error('Error ' + response.status);
        error.response = response;
        throw error;
      }
    })
    .catch(error => dispatch(loginError(error.message)))
};


person Samir Kumar    schedule 22.06.2020    source источник


Ответы (3)


Я думаю, вы должны оставить initialState со значениями по умолчанию, использовать redux-thunk и отправить действие в начале приложения для получения данных аутентификации.

const getAuth = () => {
    return async (dispatch) => {
        const [token, user] = await Promise.all([
          AsyncStorage.getItem('token'),
          AsyncStorage.getItem('creds')
        ])

        dispatch({
          type: 'GET_AUTH',
          payload: {
            isLoading: false,
            isAuthenticated: !!token,
            token,
            user: JSON.parse(creds),
            errMess: null
          }
        });
    }
}

const App = connect({}, {getAuth})(({getAuth}) => {

  useEffect(() => {
    getAuth();
  }, [])
  
  return ...
})

export const auth = async (state = {
    isLoading: false,
    isAuthenticated: false,
    token: null,
    user: null,
    errMess: null
}, action) => {
    switch (action.type) {
        case ActionTypes.GET_AUTH:
            return {
                ...state,
                ...action.payload
            };
        ...
}
person Józef Podlecki    schedule 22.06.2020
comment
Это сработало!! Но мне пришлось внести изменение в файл авторизации - мне пришлось удалить ...action.payload в ActionTypes.GET_AUTH, оставив только ...state. Я не понимаю почему, но это работает после изменения - person Samir Kumar; 23.06.2020
comment
Можете ли вы console.log(action.payload) перед возвратом состояния? - person Józef Podlecki; 23.06.2020
comment
Это работает отлично. Даже с ... полезной нагрузкой. Большое спасибо!! - person Samir Kumar; 24.06.2020

AsyncStorage является асинхронным. Использовать

const value = await AsyncStorage.getItem('token');
person strdr4605    schedule 22.06.2020
comment
Я попробовал вышеуказанное решение, но получил сообщение об ошибке «Невозможно использовать ключевое слово «ожидание» вне асинхронной функции». - person Samir Kumar; 23.06.2020
comment
Так что сделайте свою функцию асинхронной - person Roberto Zvjerković; 23.06.2020

@Samir Kumar попробуйте это

import { AsyncStorage } from 'react-native';

async functionName(){
  const token = await AsyncStorage.getItem('token');
}
person Elango    schedule 23.06.2020
comment
Я пробовал выше. Кажется, есть проблема с сохранением токена в AsyncStorage, и поэтому он возвращает нулевое значение. Не могли бы вы проверить мою функцию loginUser. - person Samir Kumar; 23.06.2020