【React Native教程】Redux入門教程
Redux在 官網 上是這麼定義的: A Predictable State Container for JS Apps ,直譯過來就是一個使用在JS應用上的可預測的狀態容器。
Redux解決的問題
React Native
本身是基於前端的 React
框架,它是通過 State
來管理頁面顯示和參數更新。如果在交互比較複雜的頁面、需要多頁面狀態傳遞或者同步更新狀態的情況,狀態管理就會比較麻煩。使用 Redux
就可以解決這些問題。
Redux的核心邏輯和概念
Redux的核心邏輯是集中定義和管理狀態和動作執行,各個頁面使用 connect
方法綁定相應的方法和狀態,並通過發送動作指令更新頁面顯示。達到狀態和操作與頁面隔離的效果。
State
State即狀態,是 React 框架最基礎的概念之一,通過更改狀態實時更新頁面顯示。
{ prop1: value1, prop2: value2, }
Action
Action是指指令或者動作。在 Redux
中,頁面不直接管理狀態,每個頁面都是通過發送 Action
間接地更新狀態。 Action
中有兩個參數,一個是 Type
,字符串類型,代表 Action
的類型和唯一標識,一個是 payload
,代表傳遞的參數,可以是任意類型。
{ type: 'EXAMPLE_ACTION', payload: 'args' }
Reducer
在 Redux
中狀態和動作都是集中管理,管理者被稱爲 Reducer
, Reducer
接收 State
和 Action
參數,根據傳過來的 Action
類型和參數進行處理並更新 State
。
function rootReducer(state = initialState, action) { if (action.type === 'FIRST_ACTION') { return Object.assign({}, state, { props: newValue }); } return state; }
Slice
在以往的 Redux
使用中,我們需要自己創建 Action
和 Reducer
,並用 Switch
或者 if else
語句區分不同的 Action
,步驟非常繁瑣。現在 Redux
官方推薦使用更方便更現代化的工具 @reduxjs/toolkit
,這個工具集成了 createAction
、 createReducer
等方法,非常方便。不過這兩個方法一般也不用,在 tookit
提供了一個新的類 Slice
,創建**Slice時也會同時創建 State
、 Reducer
和 Action
。
const mySlice = createSlice({ name: "sliceName", initialState: { prop1: "", prop2: false, }, reducers: { action1: (state, action) => { console.debug('action1 done'+action.type); }, action2: (state) => { state.prop1 = "123"; state.prop2 = true; }, }, });
在需要使用 Reducer
和 Action
時,直接抽取即可
const { action1, action2 } = authSlice.actions; const myReducer = mySlice.reducer;
Thunk
上面介紹的是普通 Action
,但如果是執行的動作需要異步執行後更新狀態的就不適用了,因此 Redux
引入了中間件 Thunk
,在引入 @reduxjs/toolkit
後創建異步 Action
方法如下:
export const doLogin = createAsyncThunk( 'user/login', async ({username, password, code}) => { return await API.fetchData({ path: 'doLogin', params: { code: code, password: AESTool.encrypt(password), userName: username, } }); }, { condition: ({username, password, code}) => { if (checkStringEmpty(username)) { HUD.show("請輸入用戶名!"); return false; } else if (checkStringEmpty(password)) { HUD.show("請輸入密碼!"); return false; } else if (checkStringEmpty(code)) { HUD.show("請輸入驗證碼!"); return false; } return true; }, dispatchConditionRejection: true } )
在上面的代碼中,在 condition
可以控制這個異步 Action
是否可以繼續執行,如果返回 false
, Action
會終止執行而且沒有回調。如果希望返回 false
後有 rejected
回調,可以設置 dispatchConditionRejection
爲 true
。
異步 Action
執行完成後,回調是在 Slice
的 extraReducers
中,異步 Action
有三個狀態: pending
、 fulfilled
和 rejected
,分別代表正在執行、成功執行和執行失敗
extraReducers: { [ doLogin.pending ]: () => { Loading.show(); }, [ doLogin.fulfilled ]: (state, action) => { Loading.hidden(); console.debug(action.payload) }, [ doLogin.rejected ]: (state, action) => { Loading.hidden(); console.warn(action.error); }, }
Store
Store是 Redux 的核心類,它的作用是管理所有的 Reducer 和中間件,並作爲參數傳遞到項目的根視圖組件中。
const middleware = [ ...getDefaultMiddleware(), CustomMiddleWare, ]; export const store = configureStore({ reducer: { auth: authReducer, common: commonReducer }, middleware, }); <Provider store={store}> <StatusBar barStyle={'light-content'}/> <App/> </Provider>
Redux在React Native中的使用
下面以一個簡單的計數器爲例講解一下如果在 React Native 中使用 Redux 。
安裝依賴
首先需要安裝 @reduxjs/toolkit ,可以使用 NPM 或者 Yarn 。
# NPM npm install @reduxjs/toolkit # Yarn yarn add @reduxjs/toolkit
然後安裝 Redux 核心庫
# NPM npm install redux # Yarn yarn add redux
創建Slice
創建 Slice
時會同步創建 State
、 Reducer
import {createSlice} from '@reduxjs/toolkit'; const countSlice = createSlice({ name: "count", initialState: { value: 0 }, reducers: { incrementAction: (state, action) => { state.value += action.payload; }, decrementAction: (state, action) => { state.value -= action.payload; }, }, }); export const {incrementAction, decrementAction } = countSlice.actions; export const countReducer = countSlice.reducer;
在這裏創建了名爲 count
的 Slice
,計算器初始值爲0,並在 Reducer
中定義了兩個 Action
: incrementAction
和 decrementAction
,根據傳過來的參數確定每次加減的數值。後面兩行 export
代碼確保外部能夠訪問這裏創建的 Action
和 reducer
。
創建Store
接下來就是創建 Store
,創建時會傳入剛剛創建的 reducer
。
注意:在頁面獲取狀態值的時候中間一定要先獲取 reducer
,然後再獲取 reducer
裏的狀態值,例如獲取 countReducer
裏的 value
: state.count.value
。
import {configureStore, createSlice, getDefaultMiddleware} from "@reduxjs/toolkit"; import {countReducer} from './slices/CountSlice' const middleware = [ ...getDefaultMiddleware(), ]; export const store = configureStore({ reducer: { count: countReducer, }, middleware, });
至此, Redux 部分就準備好了,接下來就是頁面的交互部分了。
頁面嵌入Redux
在 index.js
文件中將 Provider
更改爲 App
的根控件,並傳入 store
作爲參數:
AppRegistry.registerComponent(appName, () => ProviderContainer); const ProviderContainer = () => { return ( <Provider store={store}> <App/> </Provider> ); }
下面是 App.js
的主要代碼
class App extends Component { constructor(props) { super(props); this.state = { num: 1 } } render() { return ( <> <StatusBar barStyle="dark-content" /> <SafeAreaView> <View style={styles.container}> <TextInput style={styles.textInput} onChangeText={(text)=>{ this.setState({ num: parseInt(text) }) }}>{isNaN(this.state.num) ? 1 : this.state.num}</TextInput> <View style={styles.buttonContainer}> <TouchableOpacity style={styles.button} activeOpacity = {.9} onPress={() => { this.props.decrement(this.state.num) }}> <Text style={styles.buttonText}>-</Text> </TouchableOpacity> <Text style={styles.text}>{this.props.value}</Text> <TouchableOpacity style={styles.button} activeOpacity = {.9} onPress={() => { this.props.increment(this.state.num) }}> <Text style={styles.buttonText}>+</Text> </TouchableOpacity> </View> </View> </SafeAreaView> </> ); } } const mapStateToProps = (state) => { return { value: state.count.value, } } function mapDispatchToProps(dispatch) { return { increment: (num) => dispatch(incrementAction(num)), decrement: (num) => dispatch(decrementAction(num)), }; } export default connect(mapStateToProps, mapDispatchToProps)(App);
上面的 TextInput
用於輸入每次增加或者減小的數值,下面有一個加號按鈕和一個減號按鈕,中間是顯示當前數值的文本。
mapStateToProps
和 mapDispatchToProps
,的作用是映射 Slice
中定義的 State
和 Action
到當前頁面,在使用時直接 this.props.value
調用即可。最後通過 Redux
的 connect
方法將這些映射和當前頁的組件連接起來。
本文的 Demo 可以在 這裏 查看。
以上就是 Redux
的入門教程,想深入瞭解 Redux
的使用可以參考 Redux官方文檔
,想進一步瞭解 Redux Toolkit
可以參考 Redux Tookit官方文檔
。