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,底部導航切換,資料來源豆瓣電影
程式入口
store 和資料初始化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)
/**
* @author ling
* @email [email protected]
* @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 [email protected]
* @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 [email protected]
* @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, // 首屏資料列表 listview
banner: Banner, // 輪播
fetchload: fetchLoading, //載入中boo
});
export default allReducers;
hotshowreducer
/**
* @author ling
* @email [email protected]
* @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 [email protected]
* @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 [email protected]
* @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 [email protected]
* @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
有需要的交流的可以加個好友
相關推薦
react-native,react-redux和redux配合開發
react-native 的資料傳遞是父類傳遞給子類,子類通過this.props.** 讀取資料,這樣會造成元件多重巢狀,於是用redux可以更好的解決了資料和介面View之間的關係, 當然用到的是react-redux,是對redux的一種封裝。 react基礎的概念包
Flutter vs React Native,誰才是跨平臺應用開發的最佳利器?
隨著移動應用的需求越來越大,許多企業開始將焦點轉移到移動應用的開發上。通過引入新技術、新平臺和新
ReactJs和React Native的聯系和差異
自己 互動 server utf-8 綜合 and create 問題 mounting 1,React Js的目的 是為了使前端的V層更具組件化,能更好的復用,它能夠使用簡單的html標簽創建更多的自定義組件標簽,內部綁定事件,同時可以讓你從操作dom中解脫出來,只需要操
React Native,flexbox布局
AR star con 中間 around xbox enter rec 比例 Flexbox布局 flex:使組件在可利用的空間內動態地擴張或收縮。flex:1會使組件撐滿空間。當有多個組件都指定了flex的值,那麽誰的flex值大誰占得空間就大,占得大小的比例就
react native 更改app名稱和圖示
1.修改app的名稱 在android/src/main/res/values/strings.xml <resources> <string name="app_name">app的名字</string> </resources&g
React Native 中為IOS和Android設定不同的Style樣式,一套程式碼解決雙端顯示
React Native 開發中,大多數的元件都是IOS和Android通用的,包括大量的功能性程式碼,至少有80%以上的程式碼可以複用,而剩下的一些元件樣式/少量的程式碼會需要區分雙端,但是為了這少量的程式碼把IOS和Android完全區分這明顯不合適,程式碼複用性下降,程式碼維護量上升
React Native整合Touch ID和Face ID
前言: 使用Touch ID也稱為指紋身份驗證在移動應用程式中非常流行。Touch ID功能可保護應用程式並使其成為使用者的無縫身份驗證流程。 許多銀行應用程式,如美國銀行,發現,大通,使用Touch ID身份驗證,實現安全和無縫的身份驗證。 使用者無需在每次登入時鍵入長密碼,只
最新前端React Native,後臺Node.js,用輕量級架構開發一款直接在AppStore上線的App
前端React Native,後臺Node.js,用輕量級架構開發一款直接在AppStore上線的App,只需一週時間! 這不是一門技術多麼高深的課程 卻可以讓你快速開發一款App 一週開發一款非常“好玩兒”的上線App 這是一款已經在App store上線的App,源於講師一
react native 原生頁面跳轉到React頁面,react頁面回退到原生頁面實現。
1.最新實現方式,只要繼承ReactActivity,重寫getMainComponentName()方法。內部已實現。2.以前實現方式,實現DefaultHardwareBackBtnHandler介面,在ReactInstanceManager 設定DefaultHard
React Native入門篇—react-native-swiper的安裝和配置
注意:未經允許不可私自轉載,違者必究 React Native官方文件:https://reactnative.cn/docs/getting-started/ react-native-swiper官方教程:https://github.com/leecade/react-n
React-Native 元件的匯出和匯入
在React-Native 中如何自己定義一個元件是一件非常容易的事情。 下面是構建元件的幾種方式。 在es6中主要的關鍵詞 export default 進行修飾、之後我們就可以把自定義的元件被匯出去了。 在es5中主要使用 module.exports=HelloCom
React Native官方案例下載和編譯
1 React Native官方案例下載 React Native官方案例從0.44以後就不顯示在master中,0.44版本的Examples只更新了UIExplorer,所以可以把0.44和0.43版本都下載下來,把0.44中的UIExplorer替換0.43中的U
Facebook 正在重構 React Native,將重寫大量底層
(點選上方公眾號,可快速關注)來源:開源中國www.oschina.net/news/97129
攜程技術沙龍:React Native的框架優化和業務實踐
隨著智慧手機和移動網際網路最近幾年的迅猛發展,在其背後的開發技術也在經歷著日新月異的變化。移動開發從最早期的原生 iOS Objective C、Android Java到基於H5 Hybrid,Android外掛化/iOS動態指令碼,再到現在火熱的React
【React Native】React Native中DrawerLayoutAndroid通過點選實現展開和關閉
React Native中,DrawerLayoutAndroid元件與Android原生開發中的DrawerLayout一樣實現側滑選單的效果。通過手勢左右滑動實現拉出與退出的操作,但是需要通過點選圖示或者文字就能彈出側滑選單該怎麼做呢? 這時就需要
React Native的緩存和下載
-c 返回 end 就會 .so 刷新 modules 有時 方法 一般我們有3種數據需要緩存和下載:純文本(比如API返回,狀態標記等),圖片緩存和其他靜態文件。 純文本 純文本還是比較簡單的,RN官方模塊AsyncStorage就夠了。它就跟HTML5裏面的Local
react native 中的ReadableMap和WritableMap的使用
react native跟安卓原生互動的資料型別中,有兩個比較陌生的型別,ReadableMap和WritableMap。 ReadableMap和WritableMap,顧名思義,反正是map。 WritableMap一般是用於從原生傳給rn的資
react native 增加react-native-camera
err main 地址 技術 iss body lin yarn services 前提:已經正常運行的項目 第一步:使用命令加入react-native-camera,並且關聯react-native-camera, yarn add react-native
react native 增加react-native-storage
color ont style iss 構造 普通 storage 默認 pre 現時需要使用react-native-storage本地存儲 第一步:配置storage主文件 mystorage.js import { AsyncStorage } from ‘reac
react-native 使用 antd-mobile-rn UI進行開發app
1、建立 react-native 專案 react-native init app03 2、安裝元件 npm install antd-mobile-rn --save 3、配置按需載入 npm install babel-plugin-import --save-dev