使用Redux处理异步问题
useSelector,useDispatch
首先,也是最重要的一点。如果你不知道要不要用redux,那么最好不要用。
redux主要解决的问题是统一来源的状态管理。
- 全局state存放在store里。
store.getState()
可以获得state树。 - 给store,发送action可以通过reducer生成新的state。
store.dispatch({type:SOME_ACTION, data: {})
。 - 订阅store,或者新的state。
store.subscribe(() => store.getState())
。
React-redux主要解决的是第二条。使用connect
方法把state和actions都作为props注入到了组件里。
比如现在有一个Counter
组件。increment做为action creator。状态就是value++。
那么可以写成:
function Counter(props) { // ... return (<Button onClick={() => props.increment()}>+</Button>) } const mapStateToProps = (state) => ({ value: state.value, }); const mapActionToProps = (dispatch) => ({ increment: dispatch(increment()), }) connect(mapStateToProps, mapActionToProps)(Counter);
大概就是上面这样的。使用了react-redux的hooks呢,画风一转。整个显得清晰了很多。当然这里也不能少了redux toolkit的帮助。
要实现redux应用的完全体就少不了要创建redux的store等这些前期的配置工作。为了减少这些繁琐的配置,redux开发了toolkit这一套工具。项目代码中都有,可以参考。这里不多介绍。
使用了react-redux之后看起来就是这样了。我们在前期没有多做action(action creator)和reducer的介绍。突然出现不能体现它的简化后的好处。有一点,action和reducer通常都放在不同的地方。使用起来不是十分方便。
在新的实现中这些都在slice文件中,方便统一的管理。维护起来也好很多。
import { createSlice } from '@reduxjs/toolkit'; export const counterSlice = createSlice({ name: 'counter', initialState: { value: 0, }, reducers: { increment: state => { state.value += 1; }, decrement: state => { state.value -= 1; }, incrementByAmount: (state, action) => { state.value += action.payload; }, }, }); // Action creators are generated for each case reducer function export const { increment, decrement, incrementByAmount } = counterSlice.actions;
这是使用了redux toolkit的好处。action的部分基本不用处理。它会自动生成出来action creator。
react-redux的connect方法也省去了。
代替的方案是useSelector和useDispatch两个方法。
在ReduxCounter组件里:
// ... const ReduxCounter: React.FC<ReduxCounterProps> = props => { // ... const count = useSelector((state: RootState) => { // 1 return state.counter.value; }); const dispatch = useDispatch(); // 2 const onAdd = () => dispatch(increment()); //3 return ( <View> <Text>{count}</Text> </View> <View style={styles.buttonWrapper}> <TouchableHighlight style={styles.button} onPress={onAdd}> <View style={styles.buttonInsider}> <Text>+</Text> </View> </TouchableHighlight> ); }; export { ReduxCounter };
- 1. 使用
useSelector
获取state树对应到这个组件的状态 - 2. 使用
useDispatch
获取dispatch方法,可以发送action - 3. 在处理add点击的时候调用dispatch方法发送
increment()
action creator生成的action。
处理异步
在一般的开发中需要处理很多的网络请求,缓存读写等情况。这些都是异步的。
Redux提供了两种方法来处理异步的情况:
- createAsyncThunk
- RTK Query, redux toolkit query
下面主要通过异步缓存读写来演示如何使用这两种方法。
在React Native里用来处理简单的字符串存取的库一般是
@react-native-async-storage/async-storage
import:
import AsyncStorage from '@react-native-async-storage/async-storage';
读、写,删除:
// inside a async function const ret = await AsyncStorage.getItem('@your-key'); await AsyncStorage.setItem('@your-key', xxx-xxx-xxx); await AsyncStorage.removeItem('@your-key');
createAsyncThunk
很久以前,有一个用redux就用过的redux插件叫做redux-thunk
。
现在我们有了createAsyncThunk
。
在使用的时候和前文提到的slice的套路基本一致。首先我们来新建一个slice叫做authSlice
。
在里面填空比如:name,initialState。
reducers为空对象,处理非异步的情况。
新增的是:
- 新建相关的thunk
extraReducers
新建thunk
const authenticate = createAsyncThunk<boolean, string, any>( 'users/auth', async (token: string) => { try { await AsyncStorage.setItem(GITHUB_TOKEN_KEY, token); return true; } catch (e) { console.error('ERROR:', e); return false; } }, ); const authSlice = createSlice({ name: 'auth', initialState: { authed: false, }, reducers: {}, });
添加extraReducers
异步的thunks就放在extraReducers里:
const authSlice = createSlice({ name: 'auth', initialState: { authed: false, }, reducers: {}, extraReducers: builder => { builder.addCase(authenticate.fulfilled, state => { state.authed = true; }); builder.addCase(removeToken.rejected, state => { state.authed = false; }); }, });
最后export出去:
export { authenticate, removeToken, authSlice };
后续还要在store里绑定reducer。
export const store = configureStore({ reducer: { counter: counterSlice.reducer, auth: authSlice.reducer }, });
使用上和之前的countSlice一样:
// 读取state值const authed = useSelector((state: RootState) => state.auth.authed);
在TokenScreen.tsx文件里可以看到具体代码。
发出thunk:
const dispatch = useAppDispatch(); // 1 try { const ret = await dispatch(authenticate(text)).unwrap(); // 2 if (ret) { console.log('>result action: ', 'DONE'); } navigation.replace('Tabs'); } catch (e) { // TODO: deal with the error }
拿到useAppDispatch
方法。在src/store.ts文件里。
本质就是useDispatch
。
处理分发的thunk的结果的时候可以用redux提供的unwrap
方法直接得到结果。
在catch语句里处理错误。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
react umi 刷新或关闭浏览器时清除localStorage方式
这篇文章主要介绍了react umi 刷新或关闭浏览器时清除localStorage方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2023-10-10
最新评论