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. );

  10. }

  11. }

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

store 和数据初始化

 

 

 
  1. /**

  2. * @author ling

  3. * @email [email protected]

  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. );

  30. }

  31. }

  32.  
  33. module.exports = App;

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

 

 

 
  1. /**

  2. * @author ling

  3. * @email [email protected]

  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 [email protected]

  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 [email protected]

  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 [email protected]

  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 [email protected]

  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 (

  29. {this.props.fetchbool ? : }

  30. );

  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. { data !== undefined ?

  15. {

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

  17. return (

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

  19. {item.title}

  20. )

  21. })

  22. }

  23. : loading

  24. }

  25. );

  26. }

  27. }

  28.  
  29. function mapStateToProps(state) {

  30. return {

  31. banner: state.banner

  32. }

  33. }

  34.  
  35. let style = StyleSheet.create({

  36. title: {

  37. position: 'absolute',

  38. width: size.width,

  39. bottom: 0,

  40. color: '#ffffff',

  41. textAlign: 'right',

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

  43. }

  44. })

  45.  
  46. 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();

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

  27. //一行两个

  28. subsAry.push(

  29. );

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

  31. row.push(subsAry);

  32. subsAry = [];

  33. }

  34. }

  35. return row;

  36. }

  37. _renderRow(data) {

  38. return(

  39. {data}

  40. );

  41. }

  42. render() {

  43. let ds = new ListView.DataSource({

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

  45. });

  46. let data = this._renderList();

  47.  
  48. this.state = {

  49. dataSource: ds.cloneWithRows(data),

  50. }

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

  52. return (

  53. );

  54. }

  55. }

  56.  
  57. function mapStateToProps(state) {

  58. return {

  59. hotshows: state.hotshows

  60. }

  61. }

  62. function macthDispatchToProps(dispatch) {

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

  64. }

  65. let style = StyleSheet.create({

  66. listbox: {

  67. marginBottom: 45,

  68. }

  69. });

  70.  
  71. export default connect(mapStateToProps, macthDispatchToProps)(HotShowList);

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

 

 

 
  1. /**

  2. * @author ling

  3. * @email [email protected]

  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. Top{this.props.rank}

  19. {data.title}

  20. 评分:{data.rating.average}

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

  22. if(i > 1) return;

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

  24. return item;

  25. })}

  26. 观影人数:{data.collect_count}

  27. );

  28. }

  29. }

  30.  
  31. let style = StyleSheet.create({

  32. box: {

  33. width: width,

  34. paddingBottom: 1

  35. },

  36. avatar: {

  37. flex: 1,

  38. height: 260,

  39. },

  40. rank: {

  41. position: 'absolute',

  42. top: 0,

  43. left: 0,

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

  45. paddingVertical: 1,

  46. paddingHorizontal: 3,

  47. borderBottomRightRadius: 4

  48. },

  49. rankTxt: {

  50. fontSize: 12,

  51. color: '#ffffff'

  52. },

  53. msgbox: {

  54. position: 'absolute',

  55. bottom: 1,

  56. width: width,

  57. paddingHorizontal: 2,

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

  59. },

  60. msgrow: {

  61. flex: 1,

  62. flexDirection: 'row',

  63. justifyContent: 'space-between',

  64. },

  65. msgrowl: {

  66. fontSize: 12,

  67. color: '#ffffff'

  68. },

  69. msgrowr: {

  70. fontSize: 13,

  71. color: '#ffffff'

  72. }

  73. });

  74.  
  75. 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. { this.state.visibleSwiper ?

  12. : LOADING

  13. }

  14. );

  15. }

  16.  
  17. componentDidMount() {

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

  19. this.setState({

  20. visibleSwiper: true

  21. });

  22. clearTimeout(time);

  23. }, 200);

  24. }

 

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

github:

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

你可能感兴趣的:(react-native,react-redux和redux配合开发)