一文詳解ReactNative狀態(tài)管理rematch使用
引言
有同學(xué)反饋開發(fā) ReactNative 應(yīng)用時(shí)狀態(tài)管理不是很明白,接下來幾篇文章我們來對(duì)比下 React 及 ReactNative 狀態(tài)管理常用的幾種框架的使用和優(yōu)缺點(diǎn)。
上一篇文章介紹了 redux 的升級(jí)版 redux-toolkit 的使用,這篇文章我們來看下社區(qū)里比較出名的 redux 的升級(jí)庫:rematch。
React 和 rematch 創(chuàng)建Todo List App
下面是使用 React 和 rematch 創(chuàng)建一個(gè)簡(jiǎn)單的 Todo List App 的代碼示例,完整代碼見文章末尾:
- 首先,在命令行中輸入以下命令新建一個(gè) React 應(yīng)用:
npx create-react-app todolist
- 安裝 rematch 和 react-redux:
npm install @rematch/core react-redux
創(chuàng)建一個(gè) models.ts 文件
- 在其中繼承 rematch 的 Models,定義當(dāng)前業(yè)務(wù)的所有 model 類型
import { Models } from "@rematch/core"; //導(dǎo)出當(dāng)前業(yè)務(wù)的所有 model 的類型 export interface RootModel extends Models<RootModel> { //暫時(shí)先空著 } //創(chuàng)建并導(dǎo)出所有 model 的實(shí)例 export const models: RootModel = {}
在上面的代碼中,RootModel 是當(dāng)前業(yè)務(wù)的所有 model 接口。
rematch 中的 model 和 redux-toolkit 的 slice 概念類似,都表示一個(gè)業(yè)務(wù)的初始狀態(tài)和支持的操作。
創(chuàng)建一個(gè) todo.ts 文件
- 在其中使用 rematch 的 createModel 創(chuàng)建一個(gè) todo 的業(yè)務(wù) model:
import { createModel } from "@rematch/core"; import { State, TODO } from "../../module/todo"; import { RootModel } from "./models"; const initState : State = { todos: [ { text: "zsx clean room, model init data" } ] }; //創(chuàng)建一個(gè) model(類似 redux-toolkit 的 slice),包括一個(gè)業(yè)務(wù)的初始狀態(tài)、狀態(tài)處理和變更后的影響 //最核心的地方 ** export const todo = createModel<RootModel> () ({ name: 'todo', state: initState, //reducers 需要是純函數(shù):只依賴參數(shù)進(jìn)行計(jì)算,不使用外部數(shù)據(jù) reducers: { //與 toolkit 的 slice 不同,參數(shù)直接是 payload,更簡(jiǎn)單 addTodo: (state: State, payload: string) => { //返回新狀態(tài) return { ...state, todos: [...state.todos, {text: payload}] }; }, deleteTodo: (state: State, payload: string) => { const todos = state.todos.filter((item: TODO, index: number)=> { return item.text !== payload }); return { ...state, todos } } }, })
從上面的代碼中我們可以看到,rematch 中的 model 和 redux-toolkit 的 slice 概念類似,在其中可以指定名稱、初始狀態(tài) 和 reducers。
不同之處:
- rematch 的 reducer,參數(shù)是 payload,而不是 action,更加直接
- rematch 的 reducer,必須有返回值,否則會(huì)報(bào)錯(cuò)!
- rematch 直接導(dǎo)出 createModel 的返回值,不需要分別導(dǎo)出 actions 和 reducer
再次強(qiáng)調(diào)一下,rematch 中使用 model 表示某個(gè)業(yè)務(wù)的狀態(tài)管理,我們剛才通過 createModel 創(chuàng)建的 todo 是一個(gè) model,表示 todo 業(yè)務(wù)的狀態(tài)管理。
回到第三步創(chuàng)建的 models.ts 文件,把我們剛才創(chuàng)建的 todo 添加到 RootModel 的成員里:
import { Models } from "@rematch/core"; import {todo} from "./todo"; //導(dǎo)出當(dāng)前業(yè)務(wù)的所有 model 的類型 export interface RootModel extends Models<RootModel> { //這里的名稱就是后續(xù)調(diào)用 dispatch 的名稱 todo: typeof todo } //創(chuàng)建并導(dǎo)出所有 model 的實(shí)例 export const models: RootModel = {todo: todo}
通過上面的代碼,就可以知道,當(dāng)前所有業(yè)務(wù) model 里,有一個(gè)叫做“todo” 的 model。
同時(shí),導(dǎo)出的所有 model 的實(shí)例 models,也有一個(gè)成員 todo,它就是前面通過 createModel 創(chuàng)建的 todo model。
使用 rematch 的 init 函數(shù)創(chuàng)建 store
import { init, RematchDispatch, RematchRootState } from "@rematch/core"; import { models, RootModel } from "./model/models"; //創(chuàng)建 store,參數(shù)就是所有業(yè)務(wù)的 model export const store = init({ models }) store.subscribe( () => { console.log('store update >>> ' + JSON.stringify(store.getState())) }) store.dispatch.todo.addTodo("add from store") //導(dǎo)出類型,用于業(yè)務(wù)組件里使用 export type Store = typeof store export type Dispatch = RematchDispatch<RootModel> export type RootState = RematchRootState<RootModel>
從上面的代碼可以看到,init 函數(shù)的參數(shù)就是我們上一步導(dǎo)出的所有業(yè)務(wù) model 的對(duì)象 models。
init 返回的 store 本質(zhì)上就是 redux 的 store,因此和 redux store 一樣,也支持 subscribe 和 dispatch。
創(chuàng)建完 store 以后,我們還需要導(dǎo)出幾個(gè)類型:Store Dispatch 和 RootState,他們用于在 typescript UI 組件里獲取狀態(tài)或者分發(fā)行為。
和其他庫一樣,通過 react-redux 的 Provider 將 store 提供給組件樹:
import RematchTodoApp from './rematch/RematchTodoApp'; import { store } from './rematch/store'; const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); //分發(fā)給子元素 root.render( <Provider store={store}> <RematchTodoApp/> </Provider> );
RematchTodoApp 要?jiǎng)?chuàng)建UI 組件
創(chuàng)建 UI 組件,在其中使用 react-redux 的 useSelector 和 useDispatch 獲取狀態(tài)和分發(fā)行為:
import {useState} from "react"; import { useDispatch, useSelector } from "react-redux"; import { TODO } from "../module/todo"; import { Dispatch, RootState } from "./store"; //業(yè)務(wù)通過 useSelector 獲取數(shù)據(jù);通過 useDispatch 分發(fā) const RematchTodoApp = () => { //和 toolkit 類似,需要根據(jù) model 名稱訪問數(shù)據(jù) //參數(shù)類型就是 store 里導(dǎo)出的類型 const todos = useSelector((state: RootState) => { return state.todo.todos; }); //和 toolkit 不同的在于,需要聲明類型 //同時(shí)分發(fā)的時(shí)候也有些不同 const dispatch = useDispatch<Dispatch>(); const [text, setText] = useState(''); const handleInput = (e: any) => { setText(e.target.value) } const handleAddTodo = () => { // 分發(fā)的時(shí)候,通過 dispatch.<model name>.<reducer name> 的方式調(diào)用,參數(shù)就是 payload 的類型 //toolkit 里的寫法:dispatch(addTodo(text)) dispatch.todo.addTodo(text) setText('') } const handleDeleteTodo = (text: string) => { //toolkit 里的寫法:dispatch(deleteTodo(text)) dispatch.todo.deleteTodo(text) } return ( <div style={{display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}> <h1>This Is Rematch 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 style={{marginLeft: '12px'}} onClick={handleAddTodo}>Add Todo</button> </div> </div> ) } export default RematchTodoApp;
在上面的代碼中,我們使用 useSelector 獲取當(dāng)前業(yè)務(wù)需要的狀態(tài),因?yàn)槟玫降氖撬袠I(yè)務(wù)的數(shù)據(jù),因此需要通過 todo 的業(yè)務(wù)名稱獲取到屬于 todo 的數(shù)據(jù):
//和 toolkit 類似,需要根據(jù) model 名稱訪問數(shù)據(jù) //參數(shù)類型就是 store 里導(dǎo)出的類型 RootState const todos = useSelector((state: RootState) => { return state.todo.todos; });
需要注意的是,state.todo.todos 里的「todo」是我們第五步在 models 里增加 todo model 時(shí) key 的名稱。
隨后我們使用 useDispatch 獲取 dispatch,和 toolkit 不同的在于,需要聲明類型:
const dispatch = useDispatch<Dispatch>(); const handleAddTodo = () => { // 分發(fā)的時(shí)候,通過 dispatch.<model name>.<reducer name> 的方式調(diào)用,參數(shù)就是 payload 的類型 //toolkit 里的寫法:dispatch(addTodo(text)) dispatch.todo.addTodo(text) setText('') }
在分發(fā)行為的時(shí)候,toolkit 是這樣:dispatch(addTodo(text)),rematch 是這樣:dispatch.todo.addTodo(text) ,個(gè)人感覺 rematch 這種略微好一點(diǎn),避免了層層嵌套。
總結(jié)
通過 rematch 管理狀態(tài)分這幾步:
- 繼承 rematch 的 Models,定義當(dāng)前業(yè)務(wù)的所有 model 類型
- 使用 rematch 的 createModel 創(chuàng)建一個(gè) todo 的業(yè)務(wù) model,聲明初始化狀態(tài)、reducers
- 每個(gè) reducer 的參數(shù)是 state 和 payload,必須有返回值
- 使用 rematch 的 init 函數(shù)創(chuàng)建 store,參數(shù)就是所有 model
- 導(dǎo)出 RematchDispatch RematchRootState 和 store 的類型
- 通過 Provider 分發(fā)給組件樹
- 在 UI 組件中使用 react-redux 的 useSelector 和 useDispatch 獲取狀態(tài)和分發(fā)行為
可以看到,rematch 和 redux-toolkit 有很大的相似度。
以上就是一文詳解ReactNative狀態(tài)管理rematch使用的詳細(xì)內(nèi)容,更多關(guān)于ReactNative狀態(tài)管理rematch的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- ReactNative點(diǎn)擊事件.bind(this)操作分析
- ReactNative集成個(gè)推消息推送過程詳解
- React Native 資源包拆分實(shí)戰(zhàn)分析
- React?Native與iOS?OC之間的交互示例詳解
- React?Native項(xiàng)目設(shè)置路徑別名示例
- 一文詳解ReactNative狀態(tài)管理redux-toolkit使用
- ReactNative?狀態(tài)管理redux使用詳解
- react?native?reanimated實(shí)現(xiàn)動(dòng)畫示例詳解
- React Native按鈕Touchable系列組件使用教程示例
相關(guān)文章
使用React Native創(chuàng)建以太坊錢包實(shí)現(xiàn)轉(zhuǎn)賬等功能
這篇文章主要介紹了使用React Native創(chuàng)建以太坊錢包,實(shí)現(xiàn)轉(zhuǎn)賬等功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07如何去除富文本中的html標(biāo)簽及vue、react、微信小程序中的過濾器
這篇文章主要介紹了如何去除富文本中的html標(biāo)簽及vue、react、微信小程序中的過濾器,在vue及react中經(jīng)常會(huì)遇到,今天通過實(shí)例代碼給大家講解,需要的朋友可以參考下2018-11-11React?Native中原生實(shí)現(xiàn)動(dòng)態(tài)導(dǎo)入的示例詳解
在React?Native社區(qū)中,原生動(dòng)態(tài)導(dǎo)入一直是期待已久的功能,在這篇文章中,我們將比較靜態(tài)和動(dòng)態(tài)導(dǎo)入,學(xué)習(xí)如何原生地處理動(dòng)態(tài)導(dǎo)入,以及有效實(shí)施的最佳實(shí)踐,希望對(duì)大家有所幫助2024-02-02