美文网首页
【React Native教程】Redux入门教程

【React Native教程】Redux入门教程

作者: ZephyrCo | 来源:发表于2020-08-06 11:01 被阅读0次

    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中状态和动作都是集中管理,管理者被称为ReducerReducer接收StateAction参数,根据传过来的Action类型和参数进行处理并更新State

    function rootReducer(state = initialState, action) {
      if (action.type === 'FIRST_ACTION') {
        return Object.assign({}, state, {
          props: newValue
        });
      }
      return state;
    }
    

    Slice

    在以往的Redux使用中,我们需要自己创建ActionReducer,并用Switch或者if else语句区分不同的Action,步骤非常繁琐。现在Redux官方推荐使用更方便更现代化的工具@reduxjs/toolkit,这个工具集成了createActioncreateReducer等方法,非常方便。不过这两个方法一般也不用,在tookit提供了一个新的类Slice,创建**Slice时也会同时创建StateReducerAction

    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;
            },
        },
    });
    

    在需要使用ReducerAction时,直接抽取即可

    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是否可以继续执行,如果返回falseAction会终止执行而且没有回调。如果希望返回false后有rejected回调,可以设置dispatchConditionRejectiontrue

    异步Action执行完成后,回调是在SliceextraReducers中,异步Action有三个状态:pendingfulfilledrejected,分别代表正在执行、成功执行和执行失败

    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

    StoreRedux的核心类,它的作用是管理所有的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时会同步创建StateReducer

    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;
    

    在这里创建了名为countSlice,计算器初始值为0,并在Reducer中定义了两个ActionincrementActiondecrementAction,根据传过来的参数确定每次加减的数值。后面两行export代码确保外部能够访问这里创建的Actionreducer

    创建Store

    接下来就是创建Store,创建时会传入刚刚创建的reducer

    注意:在页面获取状态值的时候中间一定要先获取reducer,然后再获取reducer里的状态值,例如获取countReducer里的valuestate.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);
    
    
    App.js

    上面的TextInput用于输入每次增加或者减小的数值,下面有一个加号按钮和一个减号按钮,中间是显示当前数值的文本。

    mapStateToPropsmapDispatchToProps,的作用是映射Slice中定义的StateAction到当前页面,在使用时直接this.props.value调用即可。最后通过Reduxconnect方法将这些映射和当前页的组件连接起来。

    以上就是Redux的入门教程,想深入了解Redux的使用可以参考官方文档,本文的Demo可以在这里查看。

    相关文章

      网友评论

          本文标题:【React Native教程】Redux入门教程

          本文链接:https://www.haomeiwen.com/subject/nbovrktx.html