React Native之DeviceEventEmitter發送和接收消息完成事件處理


今天在Demo這樣一個項目的時候,首先遇到的第一個問題就是,每次通過dialog選擇【本周、本月、本天】時,伴隨着內容重新渲染的時候,tab navigator每次都重新創建和渲染,造成性能浪費和用戶體驗差的問題

問題分析:

由於tab navigator是在render()函數中動態創建的,因此每次隨着狀態的改變,render都會重新渲染,從而導致的問題是,每次都要重新動態創建tab navigator。

解決方案

將創建好的tabNav給綁定到當前this上,如果當前tabNav已經存在,則直接返回。

偽代碼

export default class TrendingPage extends Component<Props> {
    constructor(props) {
	super(props);
        this.tabNames = ['All', 'C', 'C#', 'PHP', 'JavaScript'];
    }
 /**
     * 優化tabNav 避免每次render的時候都要重新動態的創建nav 
     * 
     *  優化效率:根據需要選擇是否重新創建TabNavigator,通常tab改變后才重新創建
     * @returns
     * @memberof TrendingPage
     */
    _tabNav() {
        if (!this.tabNav) {
            this.tabNav = createMaterialTopTabNavigator(
                this._genTabs(), {
                    tabBarOptions: {
                        tabStyle: styles.tabStyle,
                        upperCaseLabel: false, //是否標簽大寫,默認為true
                        scrollEnabled: true, // 選項卡排不下的時候,可以滾動,默認為false
                        style: {
                            backgroundColor: '#678',
                            height: 30,
                        },
                        indicatorStyle: typeAlias.indicatorStyle, // 標簽指示器的樣式
                        labelStyle: styles.labelStyle
                    }
                }
            );
        }
        return this.tabNav;
    }

    _genTabs() {
	const tabs = {};
	this.tabNames.forEach((item, index) => {
		tabs[`tab${index}`] = {
			// screen: PopTab,
			screen: props => <TrendingTabPage {...props} timeSpan={this.state.timeSpan} tabLabel={item} />,
			navigationOptions: {
				title: item
			}
		}
	})
	return tabs;
    }

    /* 省略其他代碼*/
}

但是隨之出現了接下來的問題,就是當我們通過在dialog選擇完【本周】后,導航欄不變的情況下不重新動態創建了,下面的數據也不刷新了,從而導致該功能失效。

問題分析

由於帶有信息list的screen是綁定在創建tab navigator中,因此當tab navigator不重新創建時,screen內容將不會重新渲染,那么我們又要保持當tab不改變的時候不重新創建和渲染,又想要當前tab下的內容根據用戶操作而改變。

解決方案

使用react-native官方的一個API-----DeviceEventEmitter

使用方法

componentDidMount() {
        this.loadData();
        this.timeSpanChangeListener = DeviceEventEmitter.addListener(EVENT_TYPE_TIME_SPAN_CHANGE, (timeSpan) => {  //將監聽事件綁定到當前this上的目的是在組件卸載時能撤銷事件
            this.timeSpan = timeSpan;
            this.loadData();
        })
	}

    componentWillUnmount() {
        if (this.timeSpanChangeListener) {
            this.timeSpanChangeListener.remove();
        }
    }

DeviceEventEmitter.addListener()注冊上事件,第一個參數是事件,第二個參數是事件觸發時候的回調。注意在組件卸載時撤銷事件的綁定,避免性能浪費。

    /**
     * 當從selection中選擇一個觸發的回調
     *
     * @param {*} tab 
     * @memberof TrendingPage
     */
    onSelectTimeSpan(tab) {
        this.dialog.dismiss();
        this.setState({
            timeSpan: tab
        });
        DeviceEventEmitter.emit(EVENT_TYPE_TIME_SPAN_CHANGE, tab)
    }

    /**
     * 創建一個TrendingDialog
     *
     * @returns
     * @memberof TrendingPage
     */
    renderTrendingDialog() {
        return <TrendingDialog
            ref={dialog => this.dialog=dialog}
            onSelect={tab=>this.onSelectTimeSpan(tab)}
        />
    }

然后,我們給【本周、本天、本月】添加上回調onSelectTimeSpan,當用戶操作的時候,觸發回調,然后通過DeviceEventEmitter.emit()方法觸發綁定的事件,執行回調,更新內容。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM