美文网首页RN
RN:Redux、React-Redux实践之更换主题色

RN:Redux、React-Redux实践之更换主题色

作者: 意一ineyee | 来源:发表于2019-08-28 11:10 被阅读0次
    为App根组件包裹Provider组件,以便整个项目能使用Redux和React-Redux

    上一篇文章中,我们说到为了能让项目中所有的容器组件都能顺利拿到应用State,React-Redux规定我们要在应用根组件外面包一层Provider组件。

    我们需要在项目中导入一个redux-helpers的三方库。

    // AppContainer.js
    
    import React, {Component} from 'react';
    
    import {createAppContainer} from "react-navigation";
    import SwitchNavigator from './SwitchNavigator';
    
    import {createReactNavigationReduxMiddleware, createReduxContainer} from 'react-navigation-redux-helpers';
    import {connect} from 'react-redux';
    
    // 不使用Redux之前,我们是直接导出AppContainer,现在就不直接导出它了,而是给它包裹几层再到出去
    const AppContainer = createAppContainer(SwitchNavigator);
    
    
    {/* 第1步,使用react-navigation-redux-helpers,给AppContainer包裹一层ReduxContainer,下面都是固定写法,直接复制就行*/}
    
    // 1.1 初始化react-navigation与redux的中间件
    const reactNavigationReduxMiddleware = createReactNavigationReduxMiddleware(// 返回一个可用于store的middleware
        // 读取应用state的nav
        state => state.navigatorState,
        // 这个参数对于Redux Store来说必须是唯一的,并且与createReduxContainer下面的调用一致。
        'root',
    );
    
    // 1.2 把根组件先包装一层
    const AppContainer_ReduxContainer = createReduxContainer(// 返回包装根导航器的高阶组件,用于代替根导航器的组件
        // 我们的根导航器
        AppContainer,
        // 和上面createReactNavigationReduxMiddleware设置的key一致
        'root',
    );
    
    
    {/* 第2步,使用React-Redux,创建AppContainer_ReduxContainer的容器组件,即我们最终要使用的根组件 */}
    
    // 2.1 编写UI组件
    // 即AppContainer_ReduxContainer
    
    // 2.2 建立UI组件的props与外界的映射关系
    // 你可能会问“这个UI组件是什么添加上这些props的呢”?没错,正是这个添加映射关系的过程为该UI组件添加上了这些props
    // 输入逻辑类属性要和应用state里该组件state里的属性建立映射关系
    function mapStateToProps(state) {
        return {
            state: state.navigatorState,
        }
    }
    // 输出逻辑类属性要和dispatch(addAction)建立映射关系
    function mapDispatchToProps(dispatch) {
        return {
    
        }
    }
    
    // 2.3 使用connect方法生成UI组件对应的容器组件
    // 将来我们就是使用UI组件的容器组件了,而不是使用UI组件
    const AppContainer_ReduxContainer_Container = connect(
        mapStateToProps,
        // mapDispatchToProps,
    )(AppContainer_ReduxContainer);
    
    export {AppContainer_ReduxContainer_Container, reactNavigationReduxMiddleware};
    
    // App.js
    
    import React, {Component} from 'react';
    import {Platform, StyleSheet, Text, View} from 'react-native';
    import {AppContainer_ReduxContainer_Container} from './js/Navigator/AppContainer';
    import store from './js/store/store';
    import {Provider} from 'react-redux';
    
    export default class App extends Component {
        render() {
            return (
                // 2.4 在根组件外面包一层Provider组件,记得一定要把store={store}传递进去,
                // 这个一定要在App.js里包裹,不要想着在这里包裹完直接供外界使用了,否则因为界面的加载有先后顺序,可能会导致意外的问题
                <Provider store={store}>
                    <AppContainer_ReduxContainer_Container/>
                </Provider>
            );
        }
    }
    
    // store.js
    
    import {createStore, applyMiddleware} from 'redux';
    import rootReducer from '../reducer/rootReducer';
    
    import {reactNavigationReduxMiddleware} from '../Navigator/AppContainer';
    import thunk from 'redux-thunk';
    import {createLogger} from 'redux-logger';
    
    // 中间件
    const logger = createLogger();
    const middlewares = [
        reactNavigationReduxMiddleware,
        thunk,
        logger,// logger一定要放在最后面
    ];
    
    // 第1步:
    // 创建项目唯一的store,发现需要一个reducer
    // 所以接下来第2步,我们去创建一个reducer,回过头来填在这里,详见rootReducer.js文件
    const store = createStore(rootReducer, applyMiddleware(...middlewares));
    
    export default store;
    
    更换主题色预期效果

    行动前的考虑

    前面的文章有说过适合使用Redux和React-Redux的场景,现在我们再列一下。

    • 某个组件的state,需要共享
    • 一个组件需要改变另一个组件的state

    • 某个state,需要在任何地方都能拿到——即它应该是一个全局state
    • 一个组件需要改变某个全局state

    现在我们要编写的更换主题色,就是这样的场景:更换主题色界面的某些操作会改变某个全局state——即App的主题色,而App的主题色这个全局state需要在App的各个组件内都能被拿到。因此我们考虑使用Redux和React-Redux来实现该功能。

    当然要完整地实现该功能,需要考虑的东西确实比较多,所以一开始如果我们想不到那么多、那么远的话,就从最熟悉、最能上手的地方开始做吧,做一步思考一步,慢慢地也就做完了。现在我们先搭建更换主题色界面,并实现界面交互,这是最容易想到并实现的一步了。

    搭建更换主题色界面,并实现界面交互

    首先我们创建一个文件来专门存放App所有可更换的主题色。

    -----------AllThemeColor.js-----------
    
    const AllThemeColor = {
        Default: '#4caf50',
        Red: '#F44336',
        Pink: '#E91E63',
        Purple: '#9C27B0',
        DeepPurple: '#673AB7',
        Indigo: '#3F51B5',
        Blue: '#2196F3',
        LightBlue: '#03A9F4',
        Cyan: '#00BCD4',
        Teal: '#009688',
        Green: '#4CAF50',
        LightGreen: '#8BC34A',
        Lime: '#CDDC39',
        Yellow: '#FFEB3B',
        Amber: '#FFC107',
        Orange: '#FF9800',
        DeepOrange: '#FF5722',
        Brown: '#795548',
        Grey: '#9E9E9E',
        BlueGrey: '#607D8B',
        Black: '#000000'
    };
    
    export default AllThemeColor;
    

    接下来我们搭建更换主题色界面,项目里要求的是更换主题色界面是模态出来的。但是RN有个毛病,如果使用它的navigate方法来做模态,就得在路由配置的一开始就设置mode: 'modal',但是这会导致该navigator下所有的路由都是模态效果,而不是某个单独的路由是模态效果,因此我们得使用Modal组件来实现单个界面的模态效果。

    -----------ChangeThemeColorPage.js-----------
    
    import React, {Component} from 'react';
    import {Platform, StyleSheet, View, Modal, FlatList} from 'react-native';
    import AllThemeColor from '../../../Const/AllThemeColor';
    import ProjectNavigationBar from '../../../View/Other/ProjectNavigationBar';
    import ChangeThemeColorCell from '../../../View/My/ChangeThemeColor/ChangeThemeColorCell';
    
    // 获取所有主题色的key,组成颜色数组
    const allThemeColorArray = Object.keys(AllThemeColor);
    
    export default class ChangeThemeColorPage extends Component {
        // 这里你就感受到了,如果一个组件的state只是它自己使用,不为别人所使用的,就不用放在应用State里,那样反而使得编码复杂
        constructor(props) {
            super(props);
    
            this.state = {
                visible: false,
            }
        }
    
        render() {
            return (
                <Modal// Modal组件其实是那个背景层
                    // 背景层是否显示,即是否显示这个界面
                    visible={this.state.visible}
                    // 背景层是否透明
                    transparent={true}
                    // 背景层显示和消失时的动画效果
                    animationType={'slide'}
                    // 在安卓上用户按下设备的后退按键时触发,该属性在安卓设备上为必填,且会在modal处于开启状态时阻止BackHandler事件
                    onRequestClose={() => {
                        this.dismiss();
                    }}
                >
                    <ProjectNavigationBar/>
                    <View style={{backgroundColor: 'white', flex: 1}}>
                        <View style={styles.container}>
                            <FlatList// 整个界面用FlatList来实现九宫格的效果
                                style={styles.flatList}
                                data={allThemeColorArray}
                                renderItem={({item, index}) => this._renderItem({item, index})}
                                keyExtractor={(item) => item.key}
                                showsVerticalScrollIndicator={false}
                                numColumns={3}// 显示三列
                            />
                        </View>
                    </View>
                </Modal>
            );
        }
    
        // 显示该界面
        show() {
            this.setState({
                visible: true,
            })
        }
    
        // 消失该界面
        dismiss() {
            this.setState({
                visible: false,
            })
        }
    
        _renderItem({item, index}) {
            return (
                <ChangeThemeColorCell
                    dataDict={{colorKey: item, color: AllThemeColor[item]}}
                    didSelectThemeColor={() => {
                        // 该界面消失
                        this.dismiss();
                    }}
                />
            );
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flex: 1,
            backgroundColor: 'white',
            margin: 10,
            marginTop: Platform.OS === 'ios' ? -44 : -50,
            padding: 3,
    
            borderRadius: 4,
            shadowColor: 'gray',
            shadowOffset: {width: 2, height: 2},
            shadowOpacity: 0.5,
            shadowRadius: 2,
        },
        flatList: {
            flex: 1,
            backgroundColor: 'white',
        },
    });
    

    界面中用到了ChangeThemeColorCell,如下。

    -----------ChangeThemeColorCell.js-----------
    
    import React, {Component} from 'react';
    import {StyleSheet, Text, TouchableOpacity} from 'react-native';
    
    export default class ChangeThemeColorCell extends Component {
        render() {
            // 这个读取数据要写在这里,写在constructor里是不行的,因为数据改变后重新渲染时只走render方法,写在上面就无法读取到最新的数据
            this.dataDict = this.props.dataDict;
            if (!this.dataDict) return null;
    
            return (
                <TouchableOpacity
                    style={[styles.container, {backgroundColor: this.dataDict.color}]}
                    // 暴露一个回调出去
                    onPress={() => this.props.didSelectThemeColor()}
                >
                    <Text style={styles.text}>{this.dataDict.colorKey}</Text>
                </TouchableOpacity>
            )
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flex: 1,
            height: 120,
    
            justifyContent: 'center',
            alignItems: 'center',
    
            margin: 3,
        },
        text: {
            color: 'white',
            fontWeight: '400',
        },
    });
    

    然后在MyPagerender()方法里使用该界面。

    <ChangeThemeColorPage
        ref={changeThemeColorPage => this.changeThemeColorPage = changeThemeColorPage}
    />
    

    MyPage里点击相应的cell,模态出该界面就可以了。

    this.changeThemeColorPage.show();
    

    这样更换主题色界面就搭好了,而且界面也可以顺利的模态出来和消失掉。接下来我们还是先不考虑更换主题色这个效果,而是先考虑该功能里别的需要做的,因为那些比较简单一些。于是自然的就考虑到,点击更换主题色界面的每个cell后,是需要把主题色持久化的,这样下次打开App时才能显示相应的主题色。因此接下来,我们做主题色持久化的部分。

    持久化主题色

    这里我们写了一个专门针对持久化主题色写入与读取的工具类,Dao的意思是数据访问对象,而更换主题色也仅仅是App更换主题的一种(比如我们还可以更换主题图标),为了方便以后可能有的扩展,我们给这个工具类起名字为ThemeDao.js,而不是ThemeColorDao.js

    -----------ThemeDao.js-----------
    
    /**
     * AsyncStorage和NSUserDefaults是一样的,它们的写入和读取操作都是异步的
     */
    
    import {AsyncStorage} from "react-native";
    import AllThemeColor from "../../Const/AllThemeColor";
    
    // 持久化时的key
    const THEME_COLOR = 'themeColor';
    
    export default class ThemeDao {
        /**
         * 存储主题色
         * @param themeColor 本身就是个颜色字符串,所以可以直接存储
         */
        static saveThemeColor(themeColor) {
            AsyncStorage.setItem(THEME_COLOR, themeColor, error => {
                if (error) {
                    console.log('更换主题色,写入数据出错:', error);
                }
            });
        }
    
        /**
         * 读取主题色:因为读取主题色是异步操作,所以我们得用Promise把读取结果给它传出去
         * @returns {Promise<any> | Promise}
         */
        static getThemeColor() {
            return new Promise((resolve, reject) => {
                AsyncStorage.getItem(THEME_COLOR, (error, value) => {
                    if (error) {
                        reject(error);
                    } else {
                        if (!value) {// 数据库中还没有存主题色
                            // 那就搞个默认的主题色
                            value = AllThemeColor.Default;
    
                            // 存起来
                            this.saveThemeColor(value);
                        }
    
                        // 传出去
                        resolve(value);
                    }
                });
            });
        }
    }
    

    然后我们返回到ChangeThemeColorPage界面为点击cell更换主题色那里添加一下持久化主题色的操作。

    _renderItem({item, index}) {
        return (
            <ChangeThemeColorCell
                dataDict={{colorKey: item, color: AllThemeColor[item]}}
                didSelectThemeColor={() => {
                    // 持久化该主题色
                    ThemeDao.saveThemeColor(AllThemeColor[item]);
    
                    // 该界面消失
                    this.dismiss();
                }}
            />
        );
    }
    

    这样持久化主题色就做完了,接下来就该考虑大部头的内容了——即点击cell的时候真正的改变一下App的主题色,于是就该Redux和React-Redux部分了。

    Redux部分

    第一步:确定该功能块该有哪些action

    我们考虑,更换主题色只需要在更换主题色成功后,发出一个“更换主题色成功”的action,让App中所有订阅了该功能块State的组件都重新渲染一下就可以了。

    所以,我们只需要为这个功能块提供一个action

    -----------type.js-----------
    
    /**
     * 多数情况下,action的type会被定义成字符串常量,放在单独的文件里,方便管理
     */
    
    export default  {
        // 更换主题色
        THEME_COLOR_DID_CHANGE: 'THEME_COLOR_DID_CHANGE',
    }
    

    编写具体的action生成器和action,即点击cell更换主题色时,dispatch出用这个生成器生成的action就可以了。

    -----------ThemeAction.js-----------
    
    import Type from './type';
    
    export function changeThemeColor(themeColor) {
        return {type: Type.THEME_COLOR_DID_CHANGE, themeColor: themeColor};
    }
    

    然后在rootAction里导入并导出一下这个action

    -----------rootAction.js-----------
    
    /**
     * 项目的根aciton
     *
     * 因为项目中可能有很多action,所以我们统一到这个地方,外界导入使用的时候就方便了
     */
    
    
    // 导入所有的Action Creator
    import {changeThemeColor} from './ThemeColorAction';
    
    
    // 再导出
    export default {
         // 更换主题色
        changeThemeColor,
    }
    

    第二步:编写该功能块的reducer,并设计该功能块State的数据结构

    考虑到该功能块State只需要向外提供一个主题色,所以我们设置它的数据结构如下,并且先不给它默认值,看后面什么情况再说。

    themeState = {
        themeColor: 'red',
    };
    

    reducer收到改变主题色的action之后,把该功能块State的主题色属性改变为最新的主题色就可以了,该功能块State一变化,那么但凡订阅了该功能块State的组件就都能收到回调触发重新渲染。

    -----------themeReducer.js-----------
    
    const defaultState = {};
    const themeColorReducer = (state = defaultState, action) => {
        switch (action.type) {
            case Type.THEME_COLOR_DID_CHANGE:
                return {
                    ...state,
                    themeColor: action.themeColor,
                };
            default:
                return state;
        }
    };
    
    export default themeColorReducer;
    

    在根reducer里合并一下这个功能块reducer

    -----------rootReducer.js-----------
    
    /**
     * 项目的根reducer
     *
     * 1、因为创建store的时候只能填写一个reducer,而项目中通常会有很多reducer,
     * 所以我们就专门创建了这个reducer专门用来合并其它所有的子reducer,它不负责应用state具体的变化,只负责合并操作
     * 我们把它称为根reducer了,供创建store时使用
     *
     * 2、请注意:
     * 这个根reducer是个极其重要的东西,因为正是它合并子reducer的过程,决定了应用state里到底存放着什么东西,即什么组件的state要被放在它里面,
     * 什么组件的state想要交由应用的state来统一管理,我们就为该组件编写一个对应的子reducer来描述它state具体变化的过程并返回一个state,然后把这个reducer作为value存放在应用state里(即合并子reducer的时候)
     * 刚创建根reducer时,我们可能不知道将来会有那些组件的state会被放在应用state里来统一管理,所以可以先空着,什么时候需要什么时候往这里添加就可以。
     */
    import {combineReducers} from 'redux';
    import themeReducer from "./themeReducer.js";
    
    // 创建根reducer,合并所有子reducer(为了方便管理,我们会把子reduce分别写在单独的文件里)
    const rootReducer = combineReducers({// 这个对象就是应用的state
        // 应用state里的属性名当然可以随便起,但是为了好理解,我们就起做xxxState,为什么这么起呢?
        // 因为应用state的定义就是,它里面存放着项目中所有想被统一管理state的组件的state,所以我们起做xxxState,将来使用时很方便理解,比如state.counterState,就代表从应用state里取出counterState
        // 而且它的值就是对应的该组件的那个子reducer嘛,而reducer函数又总是返回一个state,这样xxxState = 某个state值,也很好理解
        themeState: themeReducer,
    });
    
    export default rootReducer;
    

    这样更换主题色这个功能的Redux部分我们就编写完成了,接下来编写React-Redux部分。

    React-Redux部分

    因为是在ChangeThemeColorPage里面改变App的主题色,所以它肯定是要用Redux的,那我们就以ChangeThemeColorPage为例,看下该功能的React-Redux部分怎么编写。

    第一步:在原先ChangeThemeColorPage(即UI组件)的基础上,用connect包裹UI组件,搞好容器组件和应用State、dispatch(action)的映射关系。

    function mapStateToProps(state) {
        return {
            
        }
    }
    
    function mapDispatchToProps(dispatch) {
        return {
            changeThemeColor: (themeColor) => dispatch(Action.changeThemeColor(themeColor)),
        }
    }
    
    const ChangeThemeColorPageContainer = connect(
        mapStateToProps,
        mapDispatchToProps,
        null,
        // 注意:这里千万要写上这句话,否则用了Redux后的组件是无法使用ref获取该组件的
        {forwardRef: true}
    )(ChangeThemeColorPage);
    
    export default ChangeThemeColorPageContainer;
    

    第二步:在需要发出action的地方,通过调用一下propschangeThemeColor方法(本质就是发出一个action,因为调用方法和发出action建立了映射关系)就可以了,这里我们再次修改下点击cell修改主题色的方法。

    _renderItem({item, index}) {
        return (
            <ChangeThemeColorCell
                dataDict={{colorKey: item, color: AllThemeColor[item]}}
                didSelectThemeColor={() => {
                    // 修改主题色
                    this.props.changeThemeColor(AllThemeColor[item]);
    
                    // 持久化该主题色
                    ThemeDao.saveThemeColor(AllThemeColor[item]);
    
                    // 该界面消失
                    this.dismiss();
                }}
            />
        );
    }
    

    经过以上操作,ChangeThemeColorPage的React-Redux部分就编写完毕了,很简单吧!这是我们点击cell,其实已经可以完成主题色的更换了,但是因为没有别的组件订阅更换主题色功能块State,所以我们看不出变化,那接下来我们就以ProjectNavigationBar为例,看看App中其它的组件怎么来相应主题色的更换的。

    其实和ChangeThemeColorPage一样的,我们也只需要对ProjectNavigationBar做React-Redux的部分。在ProjectNavigationBar(即UI组件)的基础上,用connect包裹UI组件,搞好容器组件和应用State、dispatch(action)的映射关系。

    function mapStateToProps(state) {
        return {
            themeState: state.themeState,
        }
    }
    
    function mapDispatchToProps(dispatch) {
        return {
    
        }
    }
    
    const ProjectNavigationBarContainer = connect(
        mapStateToProps,
        mapDispatchToProps,
    )(ProjectNavigationBar);
    
    export default ProjectNavigationBarContainer;
    

    上面代码中,因为ProjectNavigationBar只需要读取ThemeState的主题色,而不需要修改ThemeState的主题色,所以它只需要实现mapStateToProps函数就可以了,mapDispatchToProps空着就行,这正好和ChangeThemeColorPage相反。

    接下来我们只需要在render()方法里,设置导航栏的背景色从映射的ThemeState里读取就可以了,很简单吧。

    return (
        // 注意:this.props.style是外界传进来的style,一定要放在styles.container我们内部定义的style后面,否则外面设置的覆盖不了前面的,用户设置的就没效果了
        <View style={[styles.container, this.props.style, {backgroundColor: AllThemeColor[this.props.themeColorState.themeColor]}]}>
            {/* 状态栏 */}
            {statusBar}
            {/* 导航栏 */}
            {navigationBar}
        </View>
    );
    

    只要做到这一步,你就可以实现切换主题色,导航栏实时地跟着变化了,可以去试一试。

    补充初始化主题色的功能

    做完了上面的步骤,更换主题色时没什么的问题了,但是更换后,每次重新打开App,我们还没有去读取持久化的主题色呢,不读导航栏也是一片白。

    那我们第一眼的考虑是,是不是可以把持久化的主题色读取出来赋值给themeReducer.js里的defaultState,想法很好,但是没法实现,因为AsyncStorage的读取操作是异步的,根本没法给defaultState赋值,themeReducer.js界面里的代码就执行完了。因此,我们只能为初始化主题色功能新增一个action,文件变化依次如下。

    -----------type.js-----------
    
    /**
     * 多数情况下,action的type会被定义成字符串常量,放在单独的文件里,方便管理
     */
    
    export default  {
        // 初始化主题色
        INIT_THEME_COLOR: 'INIT_THEME_COLOR',
        // 更换主题色
        THEME_COLOR_DID_CHANGE: 'THEME_COLOR_DID_CHANGE',
    }
    
    -----------ThemeAction.js-----------
    
    import Type from './type';
    import ThemeDao from "../expand/dao/ThemeDao";
    
    export function changeThemeColor(themeColor) {
        return {type: Type.THEME_COLOR_DID_CHANGE, themeColor: themeColor};
    }
    
    export function initThemeColor() {
        return dispatch => {
            ThemeDao.getThemeColor()
                .then(themeColor => {
                    dispatch({type: Type.INIT_THEME_COLOR, themeColor: themeColor});
                })
        }
    }
    
    -----------rootAction.js-----------
    
    /**
     * 项目的根aciton
     *
     * 因为项目中可能有很多action,所以我们统一到这个地方,外界导入使用的时候就方便了
     */
    
    
    // 导入所有的Action Creator
    import {initThemeColor, changeThemeColor} from './ThemeAction';
    
    
    // 再导出
    export default {
        // 初始化主题
        initThemeColor,
        // 更换主题色
        changeThemeColor,
    }
    
    -----------themeReducer.js-----------
    
    import Type from '../action/type';
    
    const defaultState = {};
    
    const themeReducer = (state = defaultState, action) => {
        switch (action.type) {
            case Type.THEME_COLOR_DID_CHANGE:
                return {
                    ...state,
                    themeColor: action.themeColor,
                };
            case Type.INIT_THEME_COLOR:
                return {
                    ...state,
                    themeColor: action.themeColor,
                };
            default:
                return state;
        }
    };
    
    export default themeReducer;
    

    这就补充完毕了。接下来,我们考虑应该在哪里发出初始化主题色这个action呢?越早越好吧!在我们项目中,组件的加载顺序为AppContainer.jsSwitchNavigator.jsStackNavigator.jsDynamicBottomNavigator.js,因为前三个都没有做Redux,因为主题色变了它们也不需要跟着变,而DynamicBottomNavigator.js(即TabBar)它正好需要订阅ThemeState,所以我们索性就在它这儿初始化主题色吧,也犯不着专门去前三个组件里初始化了。

    class TabBarComponent extends Component<Props> {
        render() {
            return (
                <BottomTabBar
                    {...this.props}
                    // BottomTabBar选中时的颜色
                    activeTintColor={this.props.themeState.themeColor}
                />
            );
        }
    
        componentDidMount() {
            // 初始化主题色
            this.props.initThemeColor();
        }
    }
    
    function mapStateToProps(state) {
        return {
            themeState: state.themeState,
        }
    }
    function mapDispatchToProps(dispatch) {
        return {
            initThemeColor: () => dispatch(Action.initThemeColor()),
        }
    }
    
    const TabBarComponentContainer = connect(
        mapStateToProps,
        mapDispatchToProps,
    )(TabBarComponent);
    

    这样,主题色就初始化好了,TabBar也能响应主题色的变化了。

    额外

    至此使用Redux和React-Redux实现更换主题色的功能就基本实现了,接下来就是让App中该订阅ThemeState的组件使用React-Redux订阅订阅就行了,这里额外提醒一点App中有那么多组件都需要相应主题色的变化,那我们是不是都让它们订阅呢?这样可以,但是没必要,因为每个组件都订阅的话,项目确实显得有点臃肿。我们推荐的做法是:

    • 导航栏和TabBar自己订阅,因为它们要及时地刷新成最新颜色。
    • App第一级界面自己订阅,因为它们要及时地刷新成最新颜色,而二级、三级界面则通过第一级界面给他们传递过去。
    • 父组件自己订阅,因为它们要及时地刷新成最新颜色,而子组件则通过父组件给他们传递过去。
    • 当然,针对二级、三级界面、子组件,我们也可以不通过传递的方式做,搞个单例就可以了嘛!

    此外,项目中的自定义标签、标签排序、自定义语言、语言排序功能也都是通过Redux和React-Redux实现的,原理同上。

    相关文章

      网友评论

        本文标题:RN:Redux、React-Redux实践之更换主题色

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