AsyncStorage行为

时间:2018-05-03 07:56:56

标签: javascript reactjs asynchronous react-native expo

我碰到了AsyncStorage的一种奇怪的行为,我无法绕过头脑,并且会感谢任何能够向我解释幕后发生的事情(即失败案例和原因)

这是我正在处理的代码:

componentDidMount() {
        let _this = this;

        AsyncStorage.getItem('token', (err, data) => {
            setTimeout(() => {
                if(data !== null){
                    this.setState({isReady: true, isLoggedIn: true});
                    store.dispatch({type: t.LOGGED_IN, token: data});
                }
                else{
                    this.setState({isReady: true, isLoggedIn: false})
                    store.dispatch({type: t.LOGGED_OUT});
                }
            }, 3000)
            console.log(err);
        });
    }

正如您所看到的,我正在根据文档将callback函数传递给getItem(),这基本上告诉我用户之前是否已登录并且之后没有注销(即令牌仍然存在于某处的设备/应用程序中)。 这段代码第一次成功,检索了我通过reducer存储的旧令牌:

export default function authReducer(state = initialState, action)
{
    switch (action.type) {
        case t.LOGGED_IN:{
            AsyncStorage.setItem('token', action.token);
            return Object.assign({}, state, { isLoggedIn: true, token: action.token });
        }
        case t.LOGGED_OUT:{
            AsyncStorage.removeItem('token');
            return Object.assign({}, state, {isLoggedIn: false, token: null});
        }
        default:
            return state;
    }
}

然而,在我第二次重新加载应用时,即使在我尝试一次又一次登录后,AsyncStorage也始终无法检索数据。

我也尝试了AsyncStorage次调用的变体,即使用await.then.catch,但它们都会导致相同的结果。

我的问题是:

  1. 在失败的情况下,我认为getItem()仍会调用我传递的回调函数,因为参数列表上有error。但是,我的console.log从未在上述情况下运行。我期待一些我不应该在这里的东西吗?

  2. 为什么它只会在第二次失败?是否存在多次调用setItem()同一个密钥而不删除它会导致存储失败的情况? (我确信第一次尝试是成功的,因为我从异步存储打印了检索到的令牌)

  3. 这是否与我从Expo加载我的应用并使用CRNA初始化应用程序这一事实有关?这会以某种方式使asyncStorage持久性质量不同吗?

  4. 提前谢谢! :)

    编辑:进一步检查后,它似乎停止了打包程序并再次运行它似乎允许应用程序再次成功检索旧令牌,但如果我再次刷新应用程序,则在编辑代码后{{1}将再次失败。这是世博会和持久存储吗?

2 个答案:

答案 0 :(得分:0)

所以问题现在解决了,感谢我的一位经验丰富的程序员朋友。 事实证明我的错误是我把AsyncStorage.setItem()调用放在reducer中,他说自然是deterministic。 我在调度之前将调用移动到该类的actions.js,并且它有效!

所以而不是

export default function authReducer(state = initialState, action)
{
    switch (action.type) {
        case t.LOGGED_IN:{
            AsyncStorage.setItem('token', action.token);
            return Object.assign({}, state, { isLoggedIn: true, token: action.token });
        }
        case t.LOGGED_OUT:{
            AsyncStorage.removeItem('token');
            return Object.assign({}, state, {isLoggedIn: false, token: null});
        }
        default:
            return state;
    }
}

我做了

export default function authReducer(state = initialState, action)
{
    switch (action.type) {
        case t.LOGGED_IN:{
            return Object.assign({}, state, { isLoggedIn: true, token: action.token });
        }
        case t.LOGGED_OUT:{
            return Object.assign({}, state, {isLoggedIn: false, token: null});
        }
        default:
            return state;
    }
}

加上

export function login(data, successCB, errorCB) {
    return (dispatch) => {
        api.login(data, function (success, data, error) {
            if (success && data.exists) {
                AsyncStorage.setItem('token', data.token); //NOTE THIS
                dispatch({type: t.LOGGED_IN, token: data.token});
                successCB(data);
            }else if (error) errorCB(error)
        });
    };
}

export function signOut(successCB, errorCB){
  return (dispatch) => {
    AsyncStorage.removeItem('token'); //NOTE THIS
    dispatch({type: t.LOGGED_OUT});
    successCB();
  }
}

但我的问题仍然是persists(原谅双关语),"为什么这个简单的修改有效?我是否理解reducersdispatchers错误的机制?"

此外,deterministicAsync来电不兼容有何意义?

如果有人能向我解释那个很棒的概念! :d

答案 1 :(得分:0)

减速器必须没有副作用,因为它是纯粹的功能。

正如docs

中所述
  

它们必须是纯函数 - 函数,它们返回给定输入的完全相同的输出。他们也应该免费副作用。

副作用 - 当程序从其范围外部更改变量时

更好的方法是使用redux-saga,就像你的副作用模型的单独线程