國內(nèi)做網(wǎng)站建設知名的公司怎么優(yōu)化標題和關鍵詞排名
有同學反饋開發(fā) ReactNative 應用時狀態(tài)管理不是很明白,接下來幾篇文章我們來對比下 React 及 ReactNative 狀態(tài)管理常用的幾種框架的使用和優(yōu)缺點。
上一篇文章介紹了 redux 的使用,這篇文章我們來看下 redux 的升級版:redux-toolkit。
下面是使用 React 和 Redux-Toolkit 創(chuàng)建一個簡單的 Todo List App 的代碼示例,完整代碼見文章末尾:
- 首先,在命令行中輸入以下命令新建一個React應用:
npx create-react-app todolist
- 安裝 Redux-Toolkit 和 React-Redux:
npm install @reduxjs/toolkit react-redux
- 創(chuàng)建一個 todoSlice.ts 文件,在其中完成 action 和 reducer的創(chuàng)建「非常重要,需要保證理解」
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { State, TODO } from "../module/todo";const initState : State = {todos: [{text: "zsx clean room"}]
};//1.創(chuàng)建 Slice,每個業(yè)務一個 分片
const todoSlice = createSlice({name: 'todo', // 這個名稱似乎沒啥用initialState: initState,//最重要的 reducers 屬性,包括多個函數(shù)reducers: {addTodo: (state: State, action: PayloadAction<string>) => {return {todos: [...state.todos, {text: action.payload}]};},deleteTodo: (state: State, action: PayloadAction<string>) => {state.todos = state.todos.filter((item: TODO, index: number)=> {return item.text !== action.payload});}}
})//2.導出 slice 的 action 和 reducer
export const {addTodo, deleteTodo} = todoSlice.actions;
export default todoSlice.reducer;
在上面的代碼里,我們使用 redux-toolkit 的 createSlice 創(chuàng)建了一個分片,分片代表某個業(yè)務的數(shù)據(jù)狀態(tài)處理,比如 todoSlice 就代表 todo 業(yè)務的所有狀態(tài)處理。
createSlice 的參數(shù),分別包括 name(名稱,似乎沒啥用)、initialState(項目初始狀態(tài))和 reducers,
其中 reducers 是最重要的,它就是一個對象:
reducers: {addTodo: (...) => {//...},deleteTodo: (...) => {//...}}
對象的成員就是支持的 action 函數(shù),比如添加 todo:
addTodo: (state: State, action: PayloadAction<string>) => {//可以直接修改數(shù)據(jù)// state.todos.push({// text: action.payload// })//也可以返回新的return {todos: [...state.todos, {text: action.payload}]};}
可以看到,上面的 addTodo 類似 redux 中的 reducer,不同的在于,createSlice 中不再需要根據(jù) action type 進行 switch case 匹配,而是直接提供了函數(shù),以執(zhí)行狀態(tài)。
需要注意的是,toolkit 中的 reducer 函數(shù),可以修改原始狀態(tài)(redux 本身是需要返回新狀態(tài)的),這是因為它內(nèi)部的特殊實現(xiàn)。
- 通過 createSlice 創(chuàng)建完 todoSlice 后,下一步就是導出其中的 action 和 reducer
export const {addTodo, deleteTodo} = todoSlice.actions;
export default todoSlice.reducer;
這里再次證明,slice 是 action 和 reducer 的封裝,redux-toolkit 通過 slice 把 action 和 reducer 封裝到了一起,不再需要單獨創(chuàng)建 action 和 action creator。
通過 redux-toolkit,我們創(chuàng)建完 slice,就可以通過 slice 的 action 和 reducer 進行使用。
- 創(chuàng)建 store:
import { configureStore } from "@reduxjs/toolkit";
import todoReducer from "./todoSlice";//3.配置 store,創(chuàng)建全局唯一的 stroe
const store = configureStore({//多個 reducer,訪問數(shù)據(jù)時也需要通過多層獲取//這里的名稱,決定了獲取數(shù)據(jù)時,需要訪問的對象名稱reducer: {todo: todoReducer}
});export default store;
和 redux 不同,redux-toolkit 使用 configureStore 創(chuàng)建 store,它的好處是當有多個 reducer 時更簡單。
只需要在參數(shù)里提供一個 reducer 對象即可,有多少個業(yè)務,就給這個對象增加幾個成員。
{//多個 reducer,訪問數(shù)據(jù)時也需要通過多層獲取//這里的名稱,決定了獲取數(shù)據(jù)時,需要訪問的對象名稱reducer: {todo: todoReducer,other: otherReducer}
}
最終業(yè)務在訪問自己的數(shù)據(jù)時,通過 對象名稱可以獲取到數(shù)據(jù)。
- 上層組件通過 Provider 分發(fā)給組件樹:
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement
);//分發(fā)給子元素
root.render(<Provider store={store}><ToolkitTodoApp/></Provider>
);
這一點和 redux 一樣,都是使用 react-redux 的 Provider 提供給子組件,參數(shù)就是上一步創(chuàng)建的 store。
ToolkitTodoApp 是下一步要創(chuàng)建的 UI 組件
- 最后一步,業(yè)務組件中通過 useSelector 和 useDispatch 獲取數(shù)據(jù)和分發(fā)行為:
import {useState} from "react";
import { useDispatch, useSelector } from "react-redux";
import { State, TODO } from "../module/todo";
import store from "./store";
import { addTodo, deleteTodo } from "./todoSlice";
type RootState = ReturnType<typeof store.getState>;//業(yè)務通過 useSelector 獲取數(shù)據(jù);通過 useDispatch 分發(fā)
//比如使用 connect,更簡單易懂
const ToolkitTodoApp = () => {//獲取到的是全局的 State,需要通過 reducer 的名稱獲取到當前需要的狀態(tài)const todos = useSelector((state: RootState) => {return state.todo.todos;});const dispatch = useDispatch();const [text, setText] = useState('');const handleInput = (e: any) => {setText(e.target.value)}const handleAddTodo = () => {//todoSlice 導出的 action, 參數(shù)就是 action.payload 的類型dispatch(addTodo(text))setText('')}const handleDeleteTodo = (text: string) => {dispatch(deleteTodo(text))}return (<div style={{display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}><h1>This Is Redux-Toolkit TODO App.</h1><ul>{todos && todos.map((todo: TODO, index: any) => {return (<li key={index}><span>{todo.text}</span><button style={{marginLeft: '12px'}} onClick={() => handleDeleteTodo(todo.text)}>finish</button></li>)})}</ul><div style={{display: 'flex', flexDirection: 'row'}}><input value={text} onChange={handleInput}/><button onClick={handleAddTodo}>Add Todo</button></div></div>)
}export default ToolkitTodoApp;
從上面的代碼中可以看到,使用 redux-toolkit,組件里獲取狀態(tài)也更簡單了,不再需要寫 connect、mapStateToProps 和 mapDispatchToProps,只需要通過 react-redux 提供的 useSelector hook 即可:
const todos = useSelector((state: RootState) => {return state.todo.todos;});
需要注意的是:useSelector 里篩選自己需要的數(shù)據(jù)時,需要通過 reducer 的名稱獲取到當前需要的狀態(tài),否則會出現(xiàn)字段取不到或者取錯的情況。
比如上面的例子里,配置 store 時,todo 的 reducer 的名稱叫 “todo”,那在 todo 業(yè)務里,通過useSelector 里獲取它 state 時,就需要通過這個名稱 “todo” 去拿字段:
const store = configureStore({//多個 reducer,訪問數(shù)據(jù)時也需要通過多層獲取//這里的名稱,決定了獲取數(shù)據(jù)時,需要訪問的對象名稱reducer: {todo: todoReducer}
});
state.todo.todos;
我一開始使用 redux-toolkit 的時候,就在這一步遇到了問題。
另外,使用 useDispatch 分發(fā)行為時也需要注意:傳遞的參數(shù)是 createSlice 后導出的 action,參數(shù)類型需要和 這個 action 的 payload 類型一樣。
比如前面的 todoSlice 的 reducers 里,addTodo 的 action 類型是 PayloadAction:
addTodo: (state: State, action: PayloadAction<string>) => {...}
那在調用這個 action 時,就需要傳遞 string 類型的參數(shù):
const handleAddTodo = () => {//todoSlice 導出的 action, 參數(shù)就是 action.payload 的類型dispatch(addTodo(text))setText('')}
總結一下,通過 redux-toolkit 管理狀態(tài)分這幾步:
-
通過 createSlice 創(chuàng)建 slice,在其中指定初始狀態(tài)和支持的 action reducer
-
導出 slice 的 actions 和 reducer
-
通過 configureStore 創(chuàng)建 store,參數(shù)是一個對象,包括上一步導出的 reducer
- 需要指定好業(yè)務名稱,后續(xù)取數(shù)據(jù)要用
-
通過 Provider 分發(fā)給組件樹
-
業(yè)務組件中通過 useSelector 和 useDispatch 獲取數(shù)據(jù)和分發(fā)行為
可以看到,redux-toolkit 與 redux 相比,不需要創(chuàng)建 action creator 和 connect,簡化了開發(fā)步驟。
完整代碼:https://github.com/shixinzhang/redux-sample/tree/main/src/redux-toolkit