利用DeviceEventEmitter解决标题栏和数据列表联动问题

来源:互联网 发布:vue app.js报错 编辑:程序博客网 时间:2024/05/19 18:13

这里写图片描述

分析

这里写图片描述

页面包含TitleBar和TabNavigator组件,同时TabNavigator包含三个MessageScreen组件,而在MessageScreen中是FlatList组件,其中的Item是自定义的MessageItem组件。所以嵌套层次还是挺多的。而要实现动画中的效果,需要点击TitleBar中的编辑按钮,刷新MessageItem的状态。此处采用DeviceEventEmitter相对简单点。

当然,如果有更好的方法欢迎交流。

源码

MessageWrapperScreen.js

import React from 'react';import {StyleSheet, Text, View, ToastAndroid, BackHandler, DeviceEventEmitter, PixelRatio} from 'react-native';import {TabNavigator} from 'react-navigation';import TitleBar from "../components/TitleBar";import MessageScreen from "./MessageScreen";import theme from "../style/theme";import Constant from "../Constant";import BottomButton from "../components/BottomButton";const MessageNavigator = TabNavigator({  Tab1: {    screen: MessageScreen,    navigationOptions: ({navigation}) => ({      tabBarLabel: '全部消息'    })  },  Tab2: {    screen: MessageScreen,    navigationOptions: ({navigation}) => ({      tabBarLabel: '销售运营通知'    })  },  Tab3: {    screen: MessageScreen,    navigationOptions: ({navigation}) => ({      tabBarLabel: '小秘书通知'    })  }}, {  lazy: true,  tabBarOptions: {    activeTintColor: theme.activeColor,    inactiveTintColor: theme.inactiveColor,    upperCaseLabel: false,    labelStyle: {      fontSize: 12,      marginTop: 0,      marginBottom: 0,    },    indicatorStyle: {      backgroundColor: theme.activeColor    },    style: {      backgroundColor: '#FFF',      height: 35,    },  },});/** * 站内信Tab外层页面(包含TabNavigator) */export default class MessageWrapperScreen extends React.Component {  constructor(props) {    super(props)    this.state = {      isEditing: false,//是否正在编辑    }  }  render() {    const navigation = this.props.navigation;    return (      <View style={styles.container}>        <TitleBar          nav={navigation}          title="站内信"          rightText={this.state.isEditing ? "取消" : "编辑"}          handleRightClick={this.handleEdit}          handleBackClick={this.handleBackClick}        />        <MessageNavigator navigation={navigation}/>        {this.state.isEditing          ? (<View style={{flexDirection: 'row', height: 40}}>            <BottomButton              title="全部已读"              handleClick={this.handleAllRead}            />            <View style={{width: 1/PixelRatio.get(), height: 40, backgroundColor: 'white'}}/>            <BottomButton              title="删除"              handleClick={this.handleDelete}            />          </View>)          : null}      </View>    );  }  handleEdit = () => {    this._updateMessageList();    this.setState({      isEditing: !this.state.isEditing    });  };  handleBackClick = () => {    if (this.state.isEditing) {      this._updateMessageList();      this.setState({        isEditing: false,      });    } else {      this.props.navigation.goBack();    }  };  /**   * 发送   * @private   */  _updateMessageList = () => {    DeviceEventEmitter.emit(Constant.EVENT_UPDATE_MESSAGE_LIST, !this.state.isEditing); //发监听  };  handleAllRead = () => {    ToastAndroid.show('handleAllRead', ToastAndroid.SHORT)  };  handleDelete = () => {    ToastAndroid.show('handleDelete', ToastAndroid.SHORT)  }}const styles = StyleSheet.create({  container: {    flex: 1,    flexDirection: 'column'  },  button: {    color: 'white',  },  buttonWrapper: {    flex: 1,    paddingLeft: 10,    paddingRight: 10,    justifyContent: 'center',    alignItems: 'center',    backgroundColor: theme.activeColor,  },  btnContainer: {    flex: 1,  }});//https://reactnavigation.org/docs/intro/nestingMessageWrapperScreen.router = MessageNavigator.router;

扩展:【解决ReactNavigation中Navigator嵌套问题】

MessageScreen.js

import React from 'react';import {  StyleSheet,  View,  FlatList,  ActivityIndicator,  ToastAndroid,} from 'react-native';import LoadingView from "../components/LoadingView";import MessageItem from "../components/MessageItem";import {requestMessageList} from "../request/Apis";export default class MessageScreen extends React.Component {  constructor(props) {    super(props);    this.page = 1;    this.state = {      first: false,//首次加载,不渲染FlatList      refreshing: false,      loadMore: false,      dataList: [],      isEditing: false,    }  }  componentDidMount() {    // this.requestData(1)  }  _onPressItem = (msgId) => {    const {navigate} = this.props.navigation;    console.log(this.props.navigation);    navigate('MessageDetails', {'msgId': msgId})  };  _renderItem = (item, index) => (    <MessageItem      editable = {this.state.isEditing}      data={item}      onPressItem={this._onPressItem}    />  );  _dividerLine = () => (<View style={{height: 2}}/>);  _emptyComponent = () => (<LoadingView/>);  _onRefresh = () => {    this.setState({      refreshing: true    });    this.requestData(1)  };  _onEndReached = () => {    if (!this.state.refreshing && !this.state.loadMore) {      this.setState({        loadMore: true      });      this.requestData(++this.page);    }  };  _onFooterComponent = () => {    return this.state.loadMore ? (      <View style={styles.footerStyle}>        <ActivityIndicator          style={styles.indicatorStyle}          size="large"        />      </View>    ) : null  };  requestData = () => {    requestMessageList().then((result) => {      this.setState({        first: false,        loadMore: false,        refreshing: false,        dataList: this.page === 1 ? result.data : this.state.dataList.concat(result.data),      })    }, (error) => {      this.setState({        first: false,        loadMore: false,        refreshing: false,      });      ToastAndroid.show("error", ToastAndroid.SHORT);    });  };  render() {    let content;    if (this.state.first) {      content = (<LoadingView/>);    } else {      content = (<FlatList        initialNumToRender={10}        data={this.state.dataList}        keyExtractor={(item, index) => item.relationId}        renderItem={this._renderItem}        onRefresh={this._onRefresh}        refreshing={this.state.refreshing}        ItemSeparatorComponent={this._dividerLine}        onEndReachedThreshold={0.1}        onEndReached={this._onEndReached}        ListFooterComponent={this._onFooterComponent}      />);    }    return (      <View style={{flex: 1}}>        {content}      </View>    );  }  // render(){  //   return(<View/>)  // }}const styles = StyleSheet.create({  footerStyle: {    height: 50,    alignItems: 'center',    justifyContent: 'center',    backgroundColor: '#DDD'  },  indicatorStyle: {    height: 40,    alignItems: 'center',    justifyContent: 'center'  }});

MessageItem.js

import React from 'react';import {StyleSheet, View, Text, TouchableNativeFeedback,  Image, Dimensions,DeviceEventEmitter, ToastAndroid} from 'react-native';import moment from 'moment';import CheckBox from './CheckBox';import Constant from "../Constant";export default class MessageItem extends React.Component {  constructor(props) {    super(props);    this.state = {      checked: false,      isEditing: false,    }  }  _onPress = () => {    const item = this.props.data.item;    this.props.onPressItem(item.relationId);  };  componentWillMount() {    this.listener = DeviceEventEmitter.addListener(Constant.EVENT_UPDATE_MESSAGE_LIST, (e) => {      this.setState({        isEditing: e      });    });  }  onChange = (checked) => {    this.setState({      checked: !this.state.checked,    });  };  componentWillUnmount() {    this.listener.remove();  }  render() {    const item = this.props.data.item;    const time = moment(item.gmtCreate).format('YYYY-MM-DD');    return (      <TouchableNativeFeedback        onPress={this._onPress}        background={TouchableNativeFeedback.Ripple('#CCC', false)}>        <View style={styles.itemContainer}>          {this.state.isEditing ?            (<View style={{marginRight: 5}}>              <CheckBox                label=''                checked={this.state.checked}                onChange={this.onChange}              />            </View>)            : null}          <View style={{flex: 1}}>            <View style={styles.itemTitleContainer}>              <View style={{flexDirection: 'row', alignItems: 'center', flexShrink: 1,}}>                {item.isRead == 0 ? <View style={styles.dot}/> : null}                <Text style={styles.titleStyle} numberOfLines={1}>{item.title}</Text>              </View>              <Text style={[styles.contentStyle, {flexShrink: 0}]}>{time}</Text>            </View>            <Text style={[styles.contentStyle, {marginTop: 6}]} numberOfLines={2}>{item.summarize}</Text>          </View>        </View>      </TouchableNativeFeedback>    );  }}const styles = StyleSheet.create({  itemContainer: {    flexDirection: 'row',    alignItems: 'center',    backgroundColor: '#FFF',    padding: 8,  },  itemTitleContainer: {    flexDirection: 'row',    justifyContent: 'space-between',  },  titleStyle: {    fontSize: 15,    color: '#222',  },  contentStyle: {    fontSize: 13,    color: '#BBB',  },  dot: {    width: 6,    height: 6,    borderRadius: 3,    backgroundColor: '#FF0000',    marginRight: 3  },});

核心代码

在MessageItem中添加时间监听,并在组件卸载后移除监听

  componentWillMount() {    this.listener = DeviceEventEmitter.addListener(      Constant.EVENT_UPDATE_MESSAGE_LIST, (e) => {      this.setState({        isEditing: e      });    });  }  componentWillUnmount() {    this.listener.remove();  }

点击编辑按钮,触发事件

DeviceEventEmitter.emit(    Constant.EVENT_UPDATE_MESSAGE_LIST, !this.state.isEditing); //发监听
原创粉丝点击