使用 useReducer 时如何从 AsyncStorage 获取数据并将其添加到初始状态?

How can I get data from AsyncStorage and add it to initial state when using useReducer?

我正在使用来自 Hooks 的 useContext & useReducer & AsyncStorage.setItemuseEffect 中保存状态更新时的数据。在应用程序重新加载时,我想确保使用 AsyncStorage.getItem 获取保存的数据并将其添加到初始状态。

我尝试将带有异步的 init 函数作为第三个 属性 添加到 useReducer,但它仍然没有用接收到的数据替换初始数据。请阅读以下代码并提供帮助。

提前致谢!

我可以将数据保存到 AsyncStorage 的当前代码

  const [user, dispatch] = useReducer(userReducer, {});

  useEffect(() => {
    AsyncStorage.setItem('user', JSON.stringify(user))
  }, [user]);

  return(
    <UserContext.Provider value={{user,dispatch}}>
      {props.children}
    </UserContext.Provider>
  );
}

下面是我试过的代码,但无法将现有数据保存为初始数据。

const getUser = async function() {
  const userData = await AsyncStorage.getItem('user')
  console.log("parse");
  console.log(userData);
  console.log("parsed data");
  console.log(JSON.parse(userData));
  return userData ? JSON.parse(userData) : {};
}

export const UserContext = createContext();

const UserContextProvider = (props) => {
  const [user, dispatch] = useReducer(userReducer, {}, getUser);

  useEffect(() => {
    console.log("context");
    console.log(JSON.stringify(user));
    AsyncStorage.setItem('user', JSON.stringify(user))
  }, [user]);

  return(
    <UserContext.Provider value={{user,dispatch}}>
      {props.children}
    </UserContext.Provider>
  );
}

您的使用Reducer 的初始状态需要同步。由于 asyncStorage 不是同步的 API 您实际上不能将值作为 initialState

传递

但是您可以像下面那样使用 useEffect loading state

const getUser = async () => {
   try {
       const user = await AsyncStorage.getItem('user')
       return user ? JSON.parse(user) : {};
   } catch (e) {
       console.log('Failed to fetch the data from storage');
   }
}

export const UserContext = createContext();

const UserContextProvider = (props) => {
  const [isLoading, setIsLoading] = useState(true);
  const [user, dispatch] = useReducer(userReducer, {});

  // Loading initial Satte
  useEffect(() => {
     async function fetchUser() {
         const user = await getUser();
         setIsLoading(false);
         dispatch({type: 'INIT_REDUCER', user}); // You must handle initReducer in reducer
     }
     fetchUser();
 }, []);

  useEffect(() => {
    if(user) {
        // This check is required to avoid initial writing to asyncStorage
        console.log("context");
        console.log(JSON.stringify(user));
        AsyncStorage.setItem('user', JSON.stringify(user))
    }
  }, [user]);

  if(isLoading) {
     return (
       <View> 
           <Text>Loading...</Text> 
       </View>
     );
  }
  return(
    <UserContext.Provider value={{user,dispatch}}>
      {props.children}
    </UserContext.Provider>
  );
} 

谢谢! 根据以下建议更新和工作代码并进行了细微更改。

const getUser = async () => {
  try {
    const user = await AsyncStorage.getItem('user')
    return user ? JSON.parse(user) : {};
  } catch (e) {
    console.log('Failed to fetch the data from storage');
  }
}
export const UserContext = createContext();

const UserContextProvider = (props) => {
  const [user, dispatch] = useReducer(userReducer, {});

  // Loading initial Satte
  useEffect(() => {
     async function fetchUser() {
       const user = await getUser();
       dispatch({type: 'ADD_USER', user});
     }
     fetchUser();
  }, []);

  // Update AsyncStorage when user is updated
  useEffect(() => {
    // This check is required to avoid initial writing to asyncStorage
    if(user) {
        AsyncStorage.setItem('user', JSON.stringify(user))
    }
  }, [user]);


  return(
    <UserContext.Provider value={{user,dispatch}}>
      {props.children}
    </UserContext.Provider>
  );
}