react-native,react-redux和redux配合开发

来源:互联网 发布:淘宝天猫内部优惠券群 编辑:程序博客网 时间:2024/05/22 13:30

react-native 的数据传递是父类传递给子类,子类通过this.props.** 读取数据,这样会造成组件多重嵌套,于是用redux可以更好的解决了数据和界面View之间的关系, 当然用到的是react-redux,是对redux的一种封装。

react基础的概念包括:

1.action是纯声明式的数据结构,只提供事件的所有要素,不提供逻辑,同时尽量减少在 action 中传递的数据

2. reducer是一个匹配函数,action的发送是全局的,所有的reducer都可以捕捉到并匹配与自己相关与否,相关就拿走action中的要素进行逻辑处理,修改store中的状态,不相关就不对state做处理原样返回。reducer里就是判断语句

3.Store 就是把以上两个联系到一起的对象,Redux 应用只有一个单一的 store。当需要拆分数据处理逻辑时,你应该使用reducer组合 而不是创建多个 store。

4.Provider是一个普通组件,可以作为顶层app的分发点,它只需要store属性就可以了。它会将state分发给所有被connect的组件,不管它在哪里,被嵌套多少层

5.connect一个科里化函数,意思是先接受两个参数(数据绑定mapStateToProps和事件绑mapDispatchToProps)再接受一个参数(将要绑定的组件本身)。mapStateToProps:构建好Redux系统的时候,它会被自动初始化,但是你的React组件并不知道它的存在,因此你需要分拣出你需要的Redux状态,所以你需要绑定一个函数,它的参数是state,简单返回你需要的数据,组件里读取还是用this.props.*

6.container只做component容器和props绑定, 负责输入显示出来,component通过用户的要交互调用action这样就完整的流程就如此

来张图



流程如上,那么结构如下。


需要实现的效果如下, 顶部 一个轮播,下面listview,底部导航切换,数据来源豆瓣电影


程序入口

import React, { Component } from 'react';import { AppRegistry } from 'react-native';import App from './app/app';export default class movies extends Component {    render() {      return(        <App/>      );    }}AppRegistry.registerComponent('moives', () => moives)
store 和数据初始化

/** * @author ling * @email helloworld3q3q@gmail.com * @create date 2017-05-17 10:38:09 * @modify date 2017-05-17 10:38:09 * @desc [description]*/import { createStore, applyMiddleware, compose  } from 'redux';import { Provider } from 'react-redux';import thunk from 'redux-thunk'import React, { Component } from 'react';import Root from './containers/root';import allReducers from './reducers/allReducers';import { initHotshow, fetchLoading } from './actions/hotshow-action';const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);const store = createStoreWithMiddleware(allReducers);//初始化 进入等待 首屏数据 ajax请求store.dispatch(fetchLoading(true));class App extends Component {constructor(props) {        super(props);    }render() {return (<Provider store={ store }><Root/></Provider>);}}module.exports = App;
action纯函数,同时把action type单独写出来。在action同目录下文件types.js

/** * @author ling * @email helloworld3q3q@gmail.com * @create date 2017-05-17 10:36:44 * @modify date 2017-05-17 10:36:44 * @desc [description]*/'use strict';//首页 正在上映export const HOTSHOW_BANNER = 'HOTSHOW_BANNER';export const HOTSHOW_LIST = 'HOTSHOW_LIST';export const HOTSHOW_FETCH = 'HOTSHOW_FETCH';export const ADDMORE = 'AddMORE';
hotshow-action.js
/** * @author ling * @email helloworld3q3q@gmail.com * @create date 2017-05-12 04:56:43 * @modify date 2017-05-12 04:56:43 * @desc [description]*/import { HOTSHOW_BANNER, HOTSHOW_LIST, HOTSHOW_FETCH, ADDMORE } from './types';import { hotshowFetch } from '../middleware/index-api';export const addBanner = (data) => {return {type: HOTSHOW_BANNER,data}}//加载等待,true 显示 反之export const fetchLoading = (bool) => {return {type: HOTSHOW_FETCH,bool}}export const addList = (data) => {return {type: HOTSHOW_LIST,data}}// 正在热映 初始请求export const initHotshow = () => {return hotshowFetch(addList);}

allReducers.js 整合所有reducer

import { combineReducers } from 'redux';import { HotShowList, Banner, fetchLoading } from './hotshow/reducers'const allReducers = combineReducers({hotshows: HotShowList, // 首屏数据列表 listviewbanner: Banner, // 轮播fetchload: fetchLoading, //加载中boo});export default allReducers;

hotshowreducer

/** * @author ling * @email helloworld3q3q@gmail.com * @create date 2017-05-12 04:56:34 * @modify date 2017-05-12 04:56:34 * @desc [description]*/import { HOTSHOW_BANNER, HOTSHOW_LIST, HOTSHOW_FETCH } from '../../actions/types';export const HotShowList = (state = {}, action) => {switch (action.type) {case HOTSHOW_LIST:return Object.assign({} , state , {data : action.data});default:return state;}}export const Banner = (state = {}, action) => {switch (action.type) {case HOTSHOW_BANNER:let subjects = action.data;let data = subjects.slice(0, 5);// 前五个return Object.assign({} , state , {data : data}); default:return state;}}export const fetchLoading = (state = {}, action) => {switch (action.type) {case HOTSHOW_FETCH:return Object.assign({} , state , {data : action.bool});default:return state;}}

api 数据请求

/** * @author ling * @email helloworld3q3q@gmail.com * @create date 2017-05-16 08:34:36 * @modify date 2017-05-16 08:34:36 * @desc [description]*///const hotshow = 'https://api.douban.com/v2/movie/in_theaters';// const sonshow = 'https://api.douban.com/v2/movie/coming_soon';// const usshow = 'https://api.douban.com/v2/movie/us_box';// const nearcinemas = 'http://m.maoyan.com/cinemas.json';const hotshow = 'http://192.168.×.9:8080/weixin/hotshow.json';const sonshow = 'http://192.168.×.9:8080/weixin/sonshow.json';const usshow = 'http://192.168.×.9:8080/weixin/usshow.json';const nearcinemas = 'http://192.168.×.9:8080/weixin/nearcinemas.json';import { initHotshow, fetchLoading } from '../actions/hotshow-action';export function hotshowFetch(action) {return (dispatch) => {fetch(hotshow).then(res => res.json()).then(json => {dispatch(action(json));dispatch(fetchLoading(false));}).catch(msg => console.log('hotshowList-err  '+ msg));}}

containers\hotshow\index

/** * @author ling * @email helloworld3q3q@gmail.com * @create date 2017-05-17 10:44:56 * @modify date 2017-05-17 10:44:56 * @desc [description]*/import React, { Component } from 'react';import { View, ScrollView }  from 'react-native';import { bindActionCreators } from 'redux';import { connect } from 'react-redux';import { size } from '../../util/style';import HotShowList from './hotshow-list';import Loading from '../../compoments/comm/loading'import { fetchLoading, initHotshow } from '../../actions/hotshow-action';class hotshow extends Component {componentWillMount() {let _that = this;let time = setTimeout(function(){//请求数据_that.props.initHotshowAction();clearTimeout(time);}, 1500);}render() {return (<View >{this.props.fetchbool ? <Loading/> : <HotShowList/> }</View>);}}function mapStateToProps(state) {    return {        fetchbool: state.fetchload.data,hotshows: state.hotshows.data    }}function macthDispatchToProps(dispatch) {    return bindActionCreators({initHotshowAction: initHotshow,}, dispatch);}export default connect(mapStateToProps, macthDispatchToProps)(hotshow);
BannerCtn 轮播用的swiper 插件, 但swiper加入 listview 有个bug就是图片不显示,结尾做答
import React, { Component } from 'react';import { Text, StyleSheet, View, Image } from 'react-native';import { connect } from 'react-redux';import { bindActionCreators } from 'redux';import Swiper from 'react-native-swiper';import { addBanner } from '../../actions/hotshow-action';import { size } from '../../util/style';class BannerCtn extends Component {        render() {        let data = this.props.banner.data;        return (            <View style={{height: 200}}>            { data !== undefined ?                 <Swiper height={200} autoplay={true}>                    {                        data.map((item, i) => {                                return ( <View key={i} style={{flex: 1, height:200}}>                                    <Image style={{flex: 1}}  resizeMode='cover'                                    source={{uri: item.images.large}}/>                                    <Text style={style.title}> {item.title} </Text>                                </View>)                        })                    }                </Swiper>: <Text>loading</Text>            }            </View>        );    }}function mapStateToProps(state) {    return {        banner: state.banner    }}let style = StyleSheet.create({    title: {        position: 'absolute',        width: size.width,        bottom: 0,        color: '#ffffff',        textAlign: 'right',        backgroundColor: 'rgba(230,69,51,0.25)'    }})export default connect(mapStateToProps)(BannerCtn);
hotshow-list

import React, { Component } from 'react';import { Text, View, ListView, StyleSheet } from 'react-native';import { connect } from 'react-redux';import { bindActionCreators } from 'redux';import { addBanner } from '../../actions/hotshow-action';import Loading from '../../compoments/comm/loading';import Item from '../../compoments/hotshow/item';import Banner from './banner-ctn';import Foot from '../../compoments/comm/foot';class HotShowList extends Component {    constructor(props) {        super(props);    }    componentWillMount() {        //顶部轮播        let { hotshows, bannerAction  } = this.props;        let subs = hotshows.data.subjects;        bannerAction(subs);    }    _renderList() {        let { hotshows } = this.props;        let ary = hotshows.data.subjects, subsAry = [], row=[];        row.push(<Banner/>);        for(let i = 0, item; item = ary[i++];) {            //一行两个            subsAry.push(                <Item key={i} rank={i} data={item}/>            );            if(subsAry.length == 2) {                row.push(subsAry);                subsAry = [];            }        }        return row;    }    _renderRow(data) {        return(            <View style={{marginTop: 1, flexWrap:'wrap', flexDirection: 'row', justifyContent: 'space-between'}}>{data}</View>        );    }render() {        let ds = new ListView.DataSource({            rowHasChanged: (r1, r2) => r1 !== r2        });        let data = this._renderList();                this.state = {            dataSource: ds.cloneWithRows(data),        }        //removeClippedSubviews 处理 banner 图片不显示        return (            <View>                <View>                    <ListView removeClippedSubviews={false} dataSource={this.state.dataSource}  renderRow={this._renderRow}/>                </View>                <Foot/>           </View>);    }}function mapStateToProps(state) {    return {        hotshows: state.hotshows    }}function macthDispatchToProps(dispatch) {    return bindActionCreators({ bannerAction: addBanner}, dispatch);}let style = StyleSheet.create({    listbox: {        marginBottom: 45,    }});export default connect(mapStateToProps, macthDispatchToProps)(HotShowList);
剩下 便是foot tab 和单个item的编写

/** * @author ling * @email helloworld3q3q@gmail.com * @create date 2017-05-19 08:38:19 * @modify date 2017-05-19 08:38:19 * @desc [description]*/import React, { Component } from 'react';import { Text, View, Image, StyleSheet } from 'react-native';import { size } from '../../util/style';const width = size.width/2-0.2;class item extends Component{render() {let data = this.props.data;return(<View style={style.box}><Image resizeMode='cover' style={style.avatar} source={{uri:data.images.large}}/><View style={style.rank}><Text style={style.rankTxt}>Top{this.props.rank}</Text></View><View style={style.msgbox}><View style={style.msgrow}><Text style={style.msgrowl}>{data.title}</Text><Text style={style.msgrowr}>评分:{data.rating.average}</Text></View><View style={style.msgrow}><Text style={style.msgrowl}>{data.genres.map((item, i)=> {if(i > 1) return;i == 1 ? null : item += ',';return item;})}</Text><Text style={style.msgrowr}>观影人数:{data.collect_count}</Text></View></View></View>);}}let style = StyleSheet.create({box: {width: width,paddingBottom: 1},avatar: {flex: 1,height: 260,},rank: {position: 'absolute',top: 0,left: 0,        backgroundColor: 'rgba(255,164,51,0.6)',        paddingVertical: 1,        paddingHorizontal: 3,borderBottomRightRadius: 4    },rankTxt: {fontSize: 12,color: '#ffffff'},msgbox: {position: 'absolute',bottom: 1,width: width,paddingHorizontal: 2,backgroundColor: 'rgba(230,69,51,0.5)',},msgrow: {flex: 1,flexDirection: 'row',justifyContent: 'space-between',},msgrowl: {fontSize: 12,color: '#ffffff'},msgrowr: {fontSize: 13,color: '#ffffff'}});module.exports = item;


到此一个react-native 配合redux 编程首屏显示就大体完成了,

Swiper Image 在ListView不显示在,解决如下,测试手机微android 4.4.4,有把react-native升级为0.44.2 亲测无效

    constructor(props) {        super(props);        this.state={            visibleSwiper: false        }    }    render() {        let data = this.props.banner.data;        return (            <View style={{height: 200}}>            { this.state.visibleSwiper  ?                 <Swiper/>: <Text>LOADING</Text>            }            </View>        );    }    componentDidMount() {        let time = setTimeout(() => {            this.setState({                visibleSwiper: true            });            clearTimeout(time);        }, 200);    }

关于初始ajax数据,可以在create store的时候获取数据构建初始状态,也可以在ComponentDidMount的时候去执行action发ajax, 上文写错了,github 纠正

github:

https://github.com/helloworld3q3q/react-native-redux-demo


有需要的交流的可以加个好友




原创粉丝点击