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

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,底部导航切换,数据来源豆瓣电影

程序入口

 

 
  1. import React, { Component } from 'react';

  2. import { AppRegistry } from 'react-native';

  3.  
  4. import App from './app/app';

  5.  
  6. export default class movies extends Component {

  7. render() {

  8. return(

  9. <App/>

  10. );

  11. }

  12. }

  13.  
  14.  
  15. AppRegistry.registerComponent('moives', () => moives)

store 和数据初始化

 

 

 
  1. /**

  2. * @author ling

  3. * @email helloworld3q3q@gmail.com

  4. * @create date 2017-05-17 10:38:09

  5. * @modify date 2017-05-17 10:38:09

  6. * @desc [description]

  7. */

  8. import { createStore, applyMiddleware, compose } from 'redux';

  9. import { Provider } from 'react-redux';

  10. import thunk from 'redux-thunk'

  11. import React, { Component } from 'react';

  12. import Root from './containers/root';

  13. import allReducers from './reducers/allReducers';

  14. import { initHotshow, fetchLoading } from './actions/hotshow-action';

  15.  
  16. const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);

  17. const store = createStoreWithMiddleware(allReducers);

  18. //初始化 进入等待 首屏数据 ajax请求

  19. store.dispatch(fetchLoading(true));

  20.  
  21. class App extends Component {

  22.  
  23. constructor(props) {

  24. super(props);

  25. }

  26.  
  27. render() {

  28. return (

  29. <Provider store={ store }>

  30. <Root/>

  31. </Provider>

  32. );

  33. }

  34. }

  35.  
  36. module.exports = App;

action纯函数,同时把action type单独写出来。在action同目录下文件types.js

 

 

 
  1. /**

  2. * @author ling

  3. * @email helloworld3q3q@gmail.com

  4. * @create date 2017-05-17 10:36:44

  5. * @modify date 2017-05-17 10:36:44

  6. * @desc [description]

  7. */

  8. 'use strict';

  9.  
  10. //首页 正在上映

  11. export const HOTSHOW_BANNER = 'HOTSHOW_BANNER';

  12. export const HOTSHOW_LIST = 'HOTSHOW_LIST';

  13. export const HOTSHOW_FETCH = 'HOTSHOW_FETCH';

  14. export const ADDMORE = 'AddMORE';

hotshow-action.js

 
  1. /**

  2. * @author ling

  3. * @email helloworld3q3q@gmail.com

  4. * @create date 2017-05-12 04:56:43

  5. * @modify date 2017-05-12 04:56:43

  6. * @desc [description]

  7. */

  8. import { HOTSHOW_BANNER, HOTSHOW_LIST, HOTSHOW_FETCH, ADDMORE } from './types';

  9. import { hotshowFetch } from '../middleware/index-api';

  10.  
  11.  
  12. export const addBanner = (data) => {

  13. return {

  14. type: HOTSHOW_BANNER,

  15. data

  16. }

  17. }

  18. //加载等待,true 显示 反之

  19. export const fetchLoading = (bool) => {

  20. return {

  21. type: HOTSHOW_FETCH,

  22. bool

  23. }

  24. }

  25.  
  26.  
  27. export const addList = (data) => {

  28. return {

  29. type: HOTSHOW_LIST,

  30. data

  31. }

  32. }

  33.  
  34. // 正在热映 初始请求

  35. export const initHotshow = () => {

  36. return hotshowFetch(addList);

  37. }


allReducers.js 整合所有reducer

 

 

 
  1. import { combineReducers } from 'redux';

  2. import { HotShowList, Banner, fetchLoading } from './hotshow/reducers'

  3.  
  4. const allReducers = combineReducers({

  5. hotshows: HotShowList, // 首屏数据列表 listview

  6. banner: Banner, // 轮播

  7. fetchload: fetchLoading, //加载中boo

  8. });

  9.  
  10. export default allReducers;


hotshowreducer

 

 

 
  1. /**

  2. * @author ling

  3. * @email helloworld3q3q@gmail.com

  4. * @create date 2017-05-12 04:56:34

  5. * @modify date 2017-05-12 04:56:34

  6. * @desc [description]

  7. */

  8. import { HOTSHOW_BANNER, HOTSHOW_LIST, HOTSHOW_FETCH } from '../../actions/types';

  9.  
  10. export const HotShowList = (state = {}, action) => {

  11. switch (action.type) {

  12. case HOTSHOW_LIST:

  13. return Object.assign(

  14. {} , state , {

  15. data : action.data

  16. });

  17. default:

  18. return state;

  19. }

  20. }

  21.  
  22. export const Banner = (state = {}, action) => {

  23. switch (action.type) {

  24. case HOTSHOW_BANNER:

  25. let subjects = action.data;

  26. let data = subjects.slice(0, 5);// 前五个

  27. return Object.assign(

  28. {} , state , {

  29. data : data

  30. });

  31. default:

  32. return state;

  33. }

  34. }

  35.  
  36. export const fetchLoading = (state = {}, action) => {

  37. switch (action.type) {

  38. case HOTSHOW_FETCH:

  39. return Object.assign(

  40. {} , state , {

  41. data : action.bool

  42. });

  43. default:

  44. return state;

  45. }

  46. }


api 数据请求

 

 

 
  1. /**

  2. * @author ling

  3. * @email helloworld3q3q@gmail.com

  4. * @create date 2017-05-16 08:34:36

  5. * @modify date 2017-05-16 08:34:36

  6. * @desc [description]

  7. */

  8. //const hotshow = 'https://api.douban.com/v2/movie/in_theaters';

  9. // const sonshow = 'https://api.douban.com/v2/movie/coming_soon';

  10. // const usshow = 'https://api.douban.com/v2/movie/us_box';

  11. // const nearcinemas = 'http://m.maoyan.com/cinemas.json';

  12.  
  13. const hotshow = 'http://192.168.×.9:8080/weixin/hotshow.json';

  14. const sonshow = 'http://192.168.×.9:8080/weixin/sonshow.json';

  15. const usshow = 'http://192.168.×.9:8080/weixin/usshow.json';

  16. const nearcinemas = 'http://192.168.×.9:8080/weixin/nearcinemas.json';

  17.  
  18. import { initHotshow, fetchLoading } from '../actions/hotshow-action';

  19.  
  20. export function hotshowFetch(action) {

  21. return (dispatch) => {

  22. fetch(hotshow).then(res => res.json())

  23. .then(json => {

  24. dispatch(action(json));

  25. dispatch(fetchLoading(false));

  26. }).catch(msg => console.log('hotshowList-err '+ msg));

  27. }

  28. }


containers\hotshow\index

 

 

 
  1. /**

  2. * @author ling

  3. * @email helloworld3q3q@gmail.com

  4. * @create date 2017-05-17 10:44:56

  5. * @modify date 2017-05-17 10:44:56

  6. * @desc [description]

  7. */

  8. import React, { Component } from 'react';

  9. import { View, ScrollView } from 'react-native';

  10. import { bindActionCreators } from 'redux';

  11. import { connect } from 'react-redux';

  12. import { size } from '../../util/style';

  13. import HotShowList from './hotshow-list';

  14. import Loading from '../../compoments/comm/loading'

  15. import { fetchLoading, initHotshow } from '../../actions/hotshow-action';

  16.  
  17. class hotshow extends Component {

  18.  
  19. componentWillMount() {

  20. let _that = this;

  21. let time = setTimeout(function(){

  22. //请求数据

  23. _that.props.initHotshowAction();

  24. clearTimeout(time);

  25. }, 1500);

  26. }

  27. render() {

  28. return (<View >

  29. {this.props.fetchbool ? <Loading/> : <HotShowList/> }

  30. </View>);

  31. }

  32. }

  33. function mapStateToProps(state) {

  34. return {

  35. fetchbool: state.fetchload.data,

  36. hotshows: state.hotshows.data

  37. }

  38. }

  39. function macthDispatchToProps(dispatch) {

  40. return bindActionCreators({

  41. initHotshowAction: initHotshow,

  42. }, dispatch);

  43. }

  44. export default connect(mapStateToProps, macthDispatchToProps)(hotshow);

BannerCtn 轮播用的swiper 插件, 但swiper加入 listview 有个bug就是图片不显示,结尾做答

 
  1. import React, { Component } from 'react';

  2. import { Text, StyleSheet, View, Image } from 'react-native';

  3. import { connect } from 'react-redux';

  4. import { bindActionCreators } from 'redux';

  5. import Swiper from 'react-native-swiper';

  6. import { addBanner } from '../../actions/hotshow-action';

  7. import { size } from '../../util/style';

  8.  
  9. class BannerCtn extends Component {

  10.  
  11. render() {

  12. let data = this.props.banner.data;

  13. return (

  14. <View style={{height: 200}}>

  15. { data !== undefined ?

  16. <Swiper height={200} autoplay={true}>

  17. {

  18. data.map((item, i) => {

  19. return ( <View key={i} style={{flex: 1, height:200}}>

  20. <Image style={{flex: 1}} resizeMode='cover'

  21. source={{uri: item.images.large}}/>

  22. <Text style={style.title}> {item.title} </Text>

  23. </View>)

  24. })

  25. }

  26. </Swiper>: <Text>loading</Text>

  27. }

  28. </View>

  29. );

  30. }

  31. }

  32.  
  33. function mapStateToProps(state) {

  34. return {

  35. banner: state.banner

  36. }

  37. }

  38.  
  39. let style = StyleSheet.create({

  40. title: {

  41. position: 'absolute',

  42. width: size.width,

  43. bottom: 0,

  44. color: '#ffffff',

  45. textAlign: 'right',

  46. backgroundColor: 'rgba(230,69,51,0.25)'

  47. }

  48. })

  49.  
  50. export default connect(mapStateToProps)(BannerCtn);

hotshow-list

 

 

 
  1. import React, { Component } from 'react';

  2. import { Text, View, ListView, StyleSheet } from 'react-native';

  3. import { connect } from 'react-redux';

  4. import { bindActionCreators } from 'redux';

  5. import { addBanner } from '../../actions/hotshow-action';

  6. import Loading from '../../compoments/comm/loading';

  7. import Item from '../../compoments/hotshow/item';

  8. import Banner from './banner-ctn';

  9. import Foot from '../../compoments/comm/foot';

  10.  
  11. class HotShowList extends Component {

  12. constructor(props) {

  13. super(props);

  14. }

  15.  
  16. componentWillMount() {

  17. //顶部轮播

  18. let { hotshows, bannerAction } = this.props;

  19. let subs = hotshows.data.subjects;

  20. bannerAction(subs);

  21. }

  22. _renderList() {

  23. let { hotshows } = this.props;

  24. let ary = hotshows.data.subjects, subsAry = [], row=[];

  25. row.push(<Banner/>);

  26. for(let i = 0, item; item = ary[i++];) {

  27. //一行两个

  28. subsAry.push(

  29. <Item key={i} rank={i} data={item}/>

  30. );

  31. if(subsAry.length == 2) {

  32. row.push(subsAry);

  33. subsAry = [];

  34. }

  35. }

  36. return row;

  37. }

  38. _renderRow(data) {

  39. return(

  40. <View style={{marginTop: 1, flexWrap:'wrap', flexDirection: 'row', justifyContent: 'space-between'}}>{data}</View>

  41. );

  42. }

  43. render() {

  44. let ds = new ListView.DataSource({

  45. rowHasChanged: (r1, r2) => r1 !== r2

  46. });

  47. let data = this._renderList();

  48.  
  49. this.state = {

  50. dataSource: ds.cloneWithRows(data),

  51. }

  52. //removeClippedSubviews 处理 banner 图片不显示

  53. return (

  54. <View>

  55. <View>

  56. <ListView removeClippedSubviews={false} dataSource={this.state.dataSource} renderRow={this._renderRow}/>

  57. </View>

  58. <Foot/>

  59. </View>

  60. );

  61. }

  62. }

  63.  
  64. function mapStateToProps(state) {

  65. return {

  66. hotshows: state.hotshows

  67. }

  68. }

  69. function macthDispatchToProps(dispatch) {

  70. return bindActionCreators({ bannerAction: addBanner}, dispatch);

  71. }

  72. let style = StyleSheet.create({

  73. listbox: {

  74. marginBottom: 45,

  75. }

  76. });

  77.  
  78. export default connect(mapStateToProps, macthDispatchToProps)(HotShowList);

剩下 便是foot tab 和单个item的编写

 

 

 
  1. /**

  2. * @author ling

  3. * @email helloworld3q3q@gmail.com

  4. * @create date 2017-05-19 08:38:19

  5. * @modify date 2017-05-19 08:38:19

  6. * @desc [description]

  7. */

  8. import React, { Component } from 'react';

  9. import { Text, View, Image, StyleSheet } from 'react-native';

  10. import { size } from '../../util/style';

  11.  
  12. const width = size.width/2-0.2;

  13.  
  14. class item extends Component{

  15. render() {

  16. let data = this.props.data;

  17. return(

  18. <View style={style.box}>

  19. <Image resizeMode='cover' style={style.avatar} source={{uri:data.images.large}}/>

  20. <View style={style.rank}>

  21. <Text style={style.rankTxt}>Top{this.props.rank}</Text>

  22. </View>

  23. <View style={style.msgbox}>

  24. <View style={style.msgrow}>

  25. <Text style={style.msgrowl}>{data.title}</Text>

  26. <Text style={style.msgrowr}>评分:{data.rating.average}</Text>

  27. </View>

  28. <View style={style.msgrow}>

  29. <Text style={style.msgrowl}>

  30. {data.genres.map((item, i)=> {

  31. if(i > 1) return;

  32. i == 1 ? null : item += ',';

  33. return item;

  34. })}

  35. </Text>

  36. <Text style={style.msgrowr}>观影人数:{data.collect_count}</Text>

  37. </View>

  38. </View>

  39. </View>

  40. );

  41. }

  42. }

  43.  
  44. let style = StyleSheet.create({

  45. box: {

  46. width: width,

  47. paddingBottom: 1

  48. },

  49. avatar: {

  50. flex: 1,

  51. height: 260,

  52. },

  53. rank: {

  54. position: 'absolute',

  55. top: 0,

  56. left: 0,

  57. backgroundColor: 'rgba(255,164,51,0.6)',

  58. paddingVertical: 1,

  59. paddingHorizontal: 3,

  60. borderBottomRightRadius: 4

  61. },

  62. rankTxt: {

  63. fontSize: 12,

  64. color: '#ffffff'

  65. },

  66. msgbox: {

  67. position: 'absolute',

  68. bottom: 1,

  69. width: width,

  70. paddingHorizontal: 2,

  71. backgroundColor: 'rgba(230,69,51,0.5)',

  72. },

  73. msgrow: {

  74. flex: 1,

  75. flexDirection: 'row',

  76. justifyContent: 'space-between',

  77. },

  78. msgrowl: {

  79. fontSize: 12,

  80. color: '#ffffff'

  81. },

  82. msgrowr: {

  83. fontSize: 13,

  84. color: '#ffffff'

  85. }

  86. });

  87.  
  88. module.exports = item;

 

 

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

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

 

 
  1. constructor(props) {

  2. super(props);

  3. this.state={

  4. visibleSwiper: false

  5. }

  6. }

  7.  
  8. render() {

  9. let data = this.props.banner.data;

  10. return (

  11. <View style={{height: 200}}>

  12. { this.state.visibleSwiper ?

  13. <Swiper/>: <Text>LOADING</Text>

  14. }

  15. </View>

  16. );

  17. }

  18.  
  19. componentDidMount() {

  20. let time = setTimeout(() => {

  21. this.setState({

  22. visibleSwiper: true

  23. });

  24. clearTimeout(time);

  25. }, 200);

  26. }

 

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

github:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值