实例
在/app/host/components/houses/house_list.js文件中:
import React, {Component} from 'react'; import {StyleSheet, View, Text, Image, ListView, ScrollView, TouchableWithoutFeedback,TouchableOpacity} from 'react-native'; import {I18n, S, COLOR} from '../../utils/tools' import RightAddBarButton from '../common/navigatorBar/rightAddBarButton' import NavigationBar from 'react-native-navbar' import HouseResource from './house_resources' import Loading from '../loading' import HouseManagePopup from '../helpPopup/house_manage_popup' import RefreshInfiniteListView from '../refresh_infinite_list_view' import HouseNothing from './house_nothing' const ds = new ListView.DataSource({ rowHasChanged: (row1, row2) => row1 !== row2 }) export default class HouseList extends Component { static contextTypes = { page: React.PropTypes.object }; constructor(props) { super(props) } componentDidMount() { const {actions} = this.props actions.fetchRoomsIfNeeded({page:1}) } render() { let titleConfig = { title: I18n.t('house.house_manage'), } return( <View style={[S.container, {backgroundColor: '#ededed'}]}> <NavigationBar title={titleConfig} rightButton = {<RightAddBarButton onPress = {() => this._onPress()}/>} /> {this._renderContent()} </View> ) } _renderContent() { var data = this.props.rooms.houses.items var status = this.props.rooms.houses.status let paging = this.props.rooms.houses.paging if (status == 0) { return ( <Loading/> ) } else { if (status == 200 && paging.total_pages == 0 || data.length == 0) { return( <View> <HouseNothing /> <TouchableOpacity onPress={()=>this.onRefresh()}> <View style={{alignItems:'center',height: 50,marginTop: 40}}> <Text style={{fontSize: 14}}>{I18n.t(`common.retry`)}</Text> </View> </TouchableOpacity> </View> ) } else { return ( <RefreshInfiniteListView ref={(list) => {this.list = list}} customize={true} initialListSize={10} dataSource={ds.cloneWithRows(data)} renderHeader={() =>this._listHeader()} renderRow={(rowData) => this._houseRenderRow(rowData)} renderSeparator={this.renderSeparator} scrollEventThrottle={10} loadedAllData={() => this.loadedAllData()} onInfinite={() => this.onInfinite()} scrollEventThrottle={10} onRefresh={() => this.onRefresh()} > </RefreshInfiniteListView> ) } } } onRefresh() { const {actions} = this.props actions.fetchRoomsIfNeeded({page:1}) } loadedAllData() { let paging = this.props.rooms.houses.paging if (paging && paging.current_page && paging.total_pages) { return paging.current_page >= paging.total_pages } } onInfinite() { const { actions } = this.props var page = this.props.rooms.houses.paging.current_page actions.fetchRoomsIfNeeded( { page: page + 1, success: () => { this.list.hideFooter() } } ) } _listHeader() { return( <TouchableWithoutFeedback onPress={()=>this._house_manage_popup()}> <View style={styles.header}> <Text style={{marginRight: 5}}>{I18n.t('house.house_manage')}</Text> <Image source = {require('./img/help_ic.png')}/> {this._manage_popup()} </View> </TouchableWithoutFeedback> ) } _manage_popup(){ return( <HouseManagePopup ref={(c) => this.HouseManagePopup = c} /> ) } _house_manage_popup(){ this.HouseManagePopup.openPopup(); } _houseRenderRow(rowData) { var house = this.props.rooms.data[`${rowData}`] var dataArray = this.props.rooms.houses.data[`${rowData}`] var rooms=[] if (!_.isEmpty(dataArray)) { _.map(dataArray,(element,index)=>{ var roomsMessages = this.props.rooms.data[`${element}`] rooms.push(roomsMessages) }) } return( <View> <View style={[styles.cell,styles.border]}> <HouseResource house={house} rooms={rooms} number={rowData}/> </View> </View> ) } renderSeparator() { return ( <View></View> ) } _onPress() { this.context.page.navigator.push({ id:'house_publish', }); } } var padding = 10 const styles = StyleSheet.create({ cell:{ marginLeft: padding, marginRight: padding, marginBottom: padding, backgroundColor: '#fafafa', }, border: { borderRadius: 2, borderWidth:0.5, borderColor:'#cdcdd3', shadowRadius: 2, shadowOpacity: 0.02, shadowOffset: { height: 1 } }, header: { marginLeft: padding, marginRight: padding, marginTop: 5, marginBottom: 5, justifyContent: 'flex-end', flexDirection: 'row', }, });HouseList即是整个一个界面的组件
static contextTypes = {
page: React.PropTypes.object
};
这段函数是从最父组件/app/modal_container.js中以下这句继承而来:
childContextTypes: {
app: React.PropTypes.object,
page: React.PropTypes.object,
},
componentdidmount是render执行完后的回调函数
componentDidMount() {
const {actions} = this.props
actions.fetchRoomsIfNeeded({page:1})
}
整个过程是render执行{this._renderContent()}这个_render_Content()方法,render完全执行完之后执行ComponentDidMount这个回调函数, 然后再顺着ComponentDidMount()以后的东西, 也就是再执行一边render中的东西, 也就是渲染页面。
但回到ComponentDidMount()回调函数中的actions.fetchRoomsIfNeeded({page:1})
这个action在/app/host/actions/roomsActions.js中:
export function fetchRoomsIfNeeded(params = {}) { return (dispatch, getState) => { if (shouldFetchRooms(getState(),params)) { return dispatch(fetchRooms(params, refresh = false)) } } }getState()为得到所有的整棵树, params即为上面函数中传进来的{page: 1}
先执行shouldFetchRooms(getState(),params)
function shouldFetchRooms(state, params) { const houses = state.rooms if (houses <= 0) { return true } else if (houses.isFetching) { return false } else { return true } }判断一些存在的值, 来验证, 然后执行 dispatch(fetchRooms(params, refresh = false))
先执行fetchRooms(params, refresh = false)
function fetchRooms(params) { return (dispatch) => { dispatch(requestRooms(params)) return Octopus.fetch({url: `/v1/houses.json`, body: {page:params.page}}) .then(response => response.json()) .then(responseData => { if (responseData.meta.status == 403) { dispatch({type: types.NEED_LOGIN, params: params}) } else { dispatch(receiveRooms(params, responseData)) params.success && params.success(responseData.data) } }) .catch(reason => { __LOG.info(` ${reason} ............................... `) }) } }
function requestRooms(params) { __LOG.info(` start fetchMessages ---------------- `) return { type: types.REQUEST_ROOMS, params: params } }这个里面基本做一些数据的验证, 所以先不看
return Octopus.fetch({url: `/v1/houses.json`, body: {page:params.page}})这句是请求url并带着参数, 成功的话执行dispatch(receiveRooms(params, responseData))
receiveRooms(params, responseData)这个函数是function receiveRooms(params, responseData) { return { type: types.RECEIVE_ROOMS, rooms: responseData.data.houses, paging: responseData.meta.paging, status: responseData.meta.status, params: params, receivedAt: Date.now() } }在/app/host/actions/actionTypes.js这个文件中找action和reducer的对应关系(当然如果写的时候这里也要注册)跳到相应type的reducer中/app/host/reducers/rooms.jscase types.RECEIVE_ROOMS: var{data,houses}=state var dataArray = data var housesData=houses.data var itemsArray=houses.items action.rooms.forEach((item, index) => { var housesArray=[] _.uniq(itemsArray.push(item.number)) if (!_.isEmpty(item.roomings)) { var roomArray=[] item.roomings.forEach((element,index)=>{ dataArray[`${element.number}`]=element _.uniq(housesArray.push(element.number)) }) housesData[`${item.number}`]=housesArray dataArray[`${item.number}`]=_.omit(item,'roomings') }else { dataArray[`${item.number}`]=item housesData[`${item.number}`]=[] } }) houses = Object.assign({},houses, { isFetching: false, items:_.uniq(itemsArray), data: housesData, paging: action.paging, query: {}, status: action.status, }) return Object.assign({}, state, {data: dataArray,houses:houses}) break;对数据进行处理和合并到State大树中,action.paging即为action中最后执行dispath函数return所稍带的参数