ReactNative系列

react-redux 使用心得

2019-04-30  本文已影响36人  _coderYoung

在 iOS 开发领域工作3年半了,都说金三银四,今天四月最后一天,工作还没有落实。想当初还是个小白的时候,一天能安排4、5个面试,如今找工作如此之难,真是慌得一比。当然,不能怨天尤人,总归是自己实力不够硬朗。
最近闲来无事,捡起了快被自己忘的一干二净的 ReactNative ,简单了写了个小项目,算是温故知新了。


Redux

Redux 单项数据流框架,其特点是严格的数据流控制,开发过程中应遵循3个原则:

1. 唯一数据源

Redux 应用中应保持数据源的唯一性,说白了整个应用中只保持一个 Store,所有组件的数据源就是这个 Store 上的状态,Store 是个树形结构,往往某一个组件或者模块的数据来源于 Store 上的某个节点。

2. 保持状态只读

Redux 强调要改变 Store 的状态只能通过 actionaction 返回对象,提供给 Redux 完成新的状态的组装。

3. 数据改变只能通过纯函数

这里的纯函数就是 Reducer ,其函数签名包含两个参数 stateaction,顾名思义就是通过 action 去改变 state,一般来说是返回一个新的 state,其函数签名大致如下export default (state = initialState, action) => {}

总结一下

Reudx 包含 StoreStateReudceraction,主要为这四部分组成:


聪明组件&傻瓜组件(容器组件&展示组件)

所谓聪明、傻瓜只是相对来说,同样也叫容器组件和展示组件。 鉴于专业性,下文一律采用容器组件和展示组件的叫法。容器组件负责将 Store 中的状态,通过 props 传递给展示组件,展示组件只负责渲染页面,无需持有状态。将一个组件拆分为容器组件和展示组件是设计 React 组件的一种模式,和 Redux 无关。


前两者的结合 react-redux

上面讲到,Redux 负责管理状态,组件拆分为容器组件和展示组件。容器组件需要状态,状态来自哪呢?当然是 Redux 。 故,可以将 Redux 和组件做一个结合,达到更好的效果,那就是 react-redux,他帮助开发者抽取了可复用的容器组件,开发者只需关注展示组件即可。
相比于 Redux ,react-redux 多了 Providerconnect 两部分

Provider

提供了 Store 的容器组件,Provider 应位于根组件最顶层,管理所有子组件。其中会检查这一次渲染时 Store 代表的 props 和上次是否一致,这样做避免了多次渲染用了不同的 Store ,所以项目中应只有一个 Store。react-redux 提供了创建 Store 的方法。

connect

一个函数,负责展示组件和容器组件的连接。大致是这样export default connect(mapStateToProps, mapDispatchToProps)(SearchBar)
这里边其实是两次函数的执行,首先 connect 函数执行并返回了另一个函数然后执行,参数是展示组件。

总结一下

不难理解 react-redux 告诉我们,展示组件仅仅负责展示,不需要持有任何状态,展示组件的所有 stateaction 全部来源于 props ,容器组件通过 props 传递给展示组件。


示例代码
Demo地址
export const HOMEPAGE_SHOWSEARCHBAR = 'HOMEPAGE/SHOWSEARCHBAR';

export const HOMEPAGE_MENU_PAGECHANGE = 'HOMEPAGE/MENU/PAGECHANGE';

export const searchBarFetch = (text) => ({
  type: HOMEPAGE_FETCH_SEARCHBAR,
  text: text
});

export const updateHomePageMenuPage = (page) => ({
  type: HOMEPAGE_MENU_PAGECHANGE,
  currentPage: page
});
const initialState = {
    homepage: {
        menuInfo: {
            items: common.menuInfos,
            currentPage: 0
        },
        gridInfos: [],
        sections: [{
            title: '',
            data: []
        }],
    },

    searchBar: {
        text: '搜一下'
    }
};

export default (state = initialState, action) => {
    switch (action.type) {
        case HOMEPAGE_FETCH_SEARCHBAR:
            {
                return {
                    ...state,
                    searchBar: {
                        text: action.text
                    }
                };
            }

        case HOMEPAGE_MENU_PAGECHANGE:
            {
                return {
                    ...state,
                    homepage: {
                        menuInfo: {
                            items: state.homepage.menuInfo.items,
                            currentPage: action.currentPage
                        },
                        gridInfos: state.homepage.gridInfos,
                        sections: state.homepage.sections
                    }
                }
            }
    }
    return state;
};
const reducers = combineReducers({
    homepageReudcer
});

export default createStore(reducers);
class HomeMenu extends Component {

    render() {

        const {menuInfos, currentPage} = this.props;

        const items = menuInfos.map(({title, icon}) => (<HomeMenuItem title={title} icon={icon} key={title}/>));

        const pageCount = Math.ceil(items.length / 10);
        let menuViews = [];
        for (let i = 0; i < pageCount; i++) {
            const itemSlices = items.slice(i * 10, i * 10 + 10);
            const view = <View style={styles.itemsView} key={i}>
                {itemSlices}
            </View>
            menuViews.push(view);
        }

        return (
            <View style={styles.container}>
                <ScrollView
                    horizontal
                    pagingEnabled={true}
                    showsHorizontalScrollIndicator={false}
                    onScroll={this._onScroll}>
                    {menuViews}
                </ScrollView>
                <PageControl
                    style={styles.pageControl}
                    numberOfPages={pageCount}
                    currentPage={currentPage}
                    currentPageIndicatorTintColor={color.primary}
                    pageIndicatorTintColor={color.gray}/>
                <View style={styles.line}/>
                <HomeGridView/>
                <View style={styles.line}/>
            </View>

        );
    }

    _onScroll = (event) => {
        const x = event.nativeEvent.contentOffset.x;
        const page = Math.round(x / common.screen.width);

        const {currentPage, setCurrentPage} = this.props;
        if (currentPage !== page) {
            setCurrentPage(page);
        }
    }
}

const styles = StyleSheet.create({
    container: {
        backgroundColor: 'white',
    },
    itemsView: {
        flexDirection: 'row',
        flexWrap: 'wrap',
        width: common.screen.width
    },
    pageControl: {
        margin: 10
    },
    line: {
        backgroundColor: color.paper,
        width: common.screen.width,
        height: 10,
    }
});

const mapStateToProps = (state) => ({menuInfos: state.homepageReudcer.homepage.menuInfo.items, currentPage: state.homepageReudcer.homepage.menuInfo.currentPage});
const mapDispatchToProps = (dispatch) => ({
    setCurrentPage: (page) => {
        dispatch(updateHomePageMenuPage(page));
    }
})

export default connect(mapStateToProps, mapDispatchToProps)(HomeMenu)


完!!!
上一篇 下一篇

猜你喜欢

热点阅读