ReactNative中集成Redux Toolkit
在下边的案例中实现一个页面
在页面中有一个按钮
点击按钮实现redux中的数据更新
并显示到页面上
1 安装相关依赖
npm install @reduxjs/toolkit
npm install react-redux
package.json
"dependencies": {
...
"@reduxjs/toolkit": "^2.0.1",
"react-redux": "^7.2.5",
"redux": "^4.1.1",
"redux-thunk": "^2.3.0"
},
2 创建configureStore
基本概念
configureStore
创建Redux存储的标准方法。它在内部使用低级Redux核心createStore方法,但对其进行封装,为存储设置提供良好的默认值,以获得更好的开发体验
import { configureStore } from '@reduxjs/toolkit'
// ...
const store = configureStore({
// 在此处添加多个createSlice
reducer: {
one: oneSlice.reducer,
two: twoSlice.reducer,
}
})
export type RootState = ReturnType<typeof store.getState>
export default store
示例
创建redux/index.ts 文件
这个ts文件主要定义了一个configureStore对象,并向外暴露
configureStore 对象中有一个reducer,reducer用来定义多个createSlice对象
同时也选择性的暴露了一个RootState类型,供组件使用
// 导入configureStore
import {configureStore} from '@reduxjs/toolkit';
import testReducer from './modules/test';
// 创建一个store对象
const store = configureStore({
reducer: {
test: testReducer,
},
});
export default store;
export type RootState = ReturnType<typeof store.getState>
3 创建createSlice
基本概念
createSlice
一个接受初始状态、reducer函数对象和“切片名称”的函数,并自动生成与reducer和状态对应的action和action types
function createSlice({
// 一个名称, 将用于action types
name: string,
// 初始状态数据
initialState: State,
// 一个包含多个reducers. Key 的名称将被用于生成actions
reducers: Record<string, ReducerFunction | ReducerAndPrepareObject>,
// 用于添加更多reducers的“builder callback”函数
extraReducers?: (builder: ActionReducerMapBuilder<State>) => void,
// slice reducer的位置偏好,由`combineSlice`和`slice.selectors`使用。默认为“name”`
reducerPath?: string,
// 选择器对象,接收切片的状态作为其第一个参数.
selectors?: Record<string, (sliceState: State, ...args: any[]) => any>,
})
示例
创建redux/modules/test.ts 文件
这个ts文件主要定义了一个createSlice对象,并向外暴露addInitialData这个action 以供组件调用
createSlice对象包含一下key
- name - 一个命名空间,将被用于 action types
- initialState - reducer的初始状态
- reducers -包含多个 “reducers”的对象。Key 名称将用于生成actions的操作
import {createSlice} from '@reduxjs/toolkit';
const channelStore = createSlice({
// 模块名
name: 'test',
// 初始化state数据
initialState: {
initialData: 0, // 初始化一个数据
},
// 编写修改数据的方法 同步方法 直接修改
reducers: {
/**
* @param {*} state 是数据仓库
* @param {*} action 是个对象 payload是真实数据
*/
addInitialData(state, action) {
console.log("==");
state.initialData = action.payload + state.initialData;
},
},
});
// 向外暴露reducers 供组件修改initialState中的数据时使用
const {addInitialData} = channelStore.actions;
export {addInitialData};
// 默认导出reducer
export default channelStore.reducer;
4 在项目根组件导入configureStore
要在rn页面渲染redux中的数据
需要用 Provider 包裹项目根组件
将暴露的configureStore 传入 store属性中
import Navigator from './js/nav/index'; // 导航入口
import { Provider } from 'react-redux'; // 导入Provider
import store from './js/redux/index'; // 导入configureStore
import 'react-native-gesture-handler';
const Root = () => {
return (
<Provider store={store}>
<Navigator />
</Provider>
);
}
export default Root;
5 在组件中使用
// 组件通信
import { Text, Button, StyleSheet, View } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { RootState } from '../../redux/index'
import { addInitialData } from '../../redux/modules/test';
const styles = StyleSheet.create({
container: {
padding: 20,
},
title: {
color: 'ba',
fontWeight: 'bold',
fontSize: 30,
},
reduxData: {
marginBottom: 10,
padding: 10,
borderRadius: 2,
backgroundColor: '#FFFAF0'
}
});
export default function ReduxBase() {
// 从store中取出test数据
const test = useSelector((state: RootState) => state.test.initialData)
// 导入dispatch函数
const dispatch = useDispatch();
// 改变redux中的数据
function changeStoreData() {
dispatch(addInitialData(1))
}
return (
<>
<View style={styles.container}>
<Text style={styles.title}>修改redux中的数据</Text>
<View style={styles.reduxData}>
<Text>redux中的数据</Text>
<Text>{test}</Text>
</View>
<Button
onPress={changeStoreData}
title="点我修改redux数据"
color="#841584"
accessibilityLabel="Learn more about this purple button"
/>
</View>
</>
);
}
异步方法
在下边的案例中
演示如何通过Redux Toolkit实现异步调用接口请求数据
并将数据最终渲染到页面上
1创建新的reducers
基本概念
createAsyncThunk
一个接受Redux操作类型字符串和应返回promise的回调函数的函数。它根据您传入的操作类型前缀生成promise生命周期操作类型,并返回一个thunk操作创建者,该创建者将运行promise回调并根据返回的promise分派生命周期操作
这个函数接受两个参数 type
和 payloadCreator
const thunk = createAsyncThunk(type,payloadCreator )
type
一个字符串,用于生成额外的Redux操作类型常量,表示异步请求的生命周期
例如,“users/requestStatus”的类型参数将生成这些操作类型
pending
:'users/requestStatus/pending'
fulfilled
:'users/requestStatus/fulfilled'
rejected
:'users/requestStatus/rejected'
payloadCreator
一个回调函数,应该返回一个包含某些异步逻辑结果的promise。它也可能同步返回一个值。如果有错误,它应该返回一个包含error实例的被拒绝的promise或一个简单的值,如描述性错误消息,或者返回一个由thunkAPI.RejectWithValue函数返回的带有RejectWithValue参数的已解析promise
payloadCreator函数可以包含计算适当结果所需的任何逻辑。这可能包括一个标准的AJAX数据获取请求、将结果组合成最终值的多个AJAX调用、与React Native AsyncStorage的交互等等
payloadCreator函数将通过两个参数调用
- arg: 一个单独的值,包含在分派thunk操作创建者时传递给它的第一个参数。这对于传入请求中可能需要的项目ID等值非常有用。如果需要传入多个值,请在分派thunk时将它们一起传递到一个对象中,如dispatch(fetchUsers({status:‘active’,sortBy:‘name’}))
- thunkAPI: 一个对象,包含通常传递给Redux thunk函数的所有参数以及其他选项
extraReducers
extraReducers允许createSlice响应并更新自己的状态,以响应除其生成的类型之外的其他操作类型
其中extraReducers接受一个回调函数 参数为 builder
createSlice({
name: 'counter',
initialState: 0,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(incrementBy, (state, action) => {
// action is inferred correctly here if using TS
})
}
})
Builder 方法
builder.addCase
添加一个Reducer来处理单一的精确动作类型
所有对builder.addCase的调用都必须在对builder.addMatcher或builder.addDefaultCase的任何调用之前进行
参数
actionCreator 一个普通的动作类型字符串,或者由createAction生成的动作创建者,可用于确定动作类型
reducer 实际Reducer功能
builder.addMatcher
允许您将传入的操作与自己的筛选函数相匹配,而不仅仅是action.type属性
如果多个匹配器reducer匹配,则所有匹配器都将按照定义的顺序执行,即使一个case reducer已经匹配。所有对builder.addMatcher的调用都必须在对builder.addCase的任何调用之后,在对buildr.addDefaultCase的任何调用之前
参数
**matcher **匹配函数。在TypeScript中,这应该是一个类型谓词函数
reducer 实际Reducer功能
示例
创建redux/modules/testasyn.ts 在这个reducers里实现异步请求数据的功能
在这个案例中
主要用到了 createAsyncThunk 和 extraReducers 处理异步请求
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
// 导入一个异步请求数据的方法
import { getData } from '../../api/index'
// 声明异步Thunk
const infoQuery = createAsyncThunk(
"testasyn/infoQuery",
async () => {
// 异步调用网络接口请求数据
const data = await getData()
return data
}
)
const channelStore = createSlice({
// 模块名
name: 'testasyn',
// 初始化state数据
initialState: {
info: {
id: '',
tag: '',
name: '',
origin: '',
content: '',
created_at: '',
updated_at: ''
}
},
reducers: {
},
// 额外的Reducers处理
extraReducers: (builder) => {
// 当异步action处理完调用
builder.addCase(infoQuery.fulfilled, (state, action) => {
state.info = action.payload;
})
// 当异步action处理中调用
builder.addCase(infoQuery.pending, (state) => {
console.log("加载中");
})
// 当异步action出错调用
builder.addCase(infoQuery.rejected, (state, action) => {
console.log("出错了");
});
}
});
// 导出actionCreater
export { infoQuery };
// 默认导出reducer
export default channelStore.reducer;
2.在configureStore中导入创建的reducers
在redux/index.ts 文件中
import { configureStore } from '@reduxjs/toolkit';
import testReducer from './modules/test';
import testAsynReducer from './modules/testasyn';
const store = configureStore({
reducer: {
test: testReducer,
testAsyn: testAsynReducer,
},
});
export default store;
export type RootState = ReturnType<typeof store.getState>
3在组件中使用
// 异步组件通信
import { Text, Pressable } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { RootState } from '../../redux';
import { infoQuery } from '../../redux/modules/testasyn';
export default function ReduxBase() {
const dispatch = useDispatch();
// 从store中取出异步的数据
const info = useSelector((state: RootState) => state.testAsyn.info)
// 触发异步操作
function getDataAsyn() {
dispatch(infoQuery())
}
return (
<>
<Pressable onPress={getDataAsyn}>
<Text>点我异步请求数据</Text>
</Pressable>
<Text>{info.id}</Text>
<Text>{info.tag}</Text>
<Text>{info.name}</Text>
<Text>{info.origin}</Text>
<Text>{info.content}</Text>
<Text>{info.created_at}</Text>
<Text>{info.updated_at}</Text>
</>
);
}