天天看點

ReactNative 學習筆記 Community- 元件,頁面通訊1.父子元件2.兄弟元件3.全局事件4. Navigator didfocus 和 Navigator傳遞方法通訊5. Redux小結

1.父子元件

ReactJS中資料的流動是單向的

父元件傳遞資料給子元件: 可以通過設定子元件的props傳遞資料給子元件。

子元件改變父元件的資料: 可以在父元件中傳一個callback(回調函數)給子元件,子元件調用callback可改變父元件的資料。

執行個體:點選子元件,改變父元件的背景色

export default class SampleOne extends Component {
    constructor(props) {
        super(props);
        this.state = {
            color: 'white',
        };
    }

    // 改變curItem的回調函數 
    _changeColor(color) {
        this.setState({ color: color });
    }

    render() {
        return (
            <View style={{ backgroundColor: this.state.color, flex: 1 }}>
                <Child text='Child one' color='red'
                    changeColor={ (color) => this._changeColor.bind(this, color) }/>
                <Child  text='Child two' color='white'
                    changeColor={ (color) => this._changeColor.bind(this, color) }/>
            </View>
        );
    }
}

class Child extends Component {
    render() {
        return (
            <Text style = {{ fontSize: 50, margin: 20 }}
                onPress={this.props.changeColor(this.props.color) }>
                {this.props.text}
            </Text>
        );
    }
}
           

2.兄弟元件

當兩個元件不是父子關系,但有相同的父元件時,将這兩個元件稱為兄弟元件。

兄弟元件不能直接互相傳送資料,此時可以将資料挂載在父元件中。

由兩個元件共享:如果元件需要資料渲染,則由父元件通過props傳遞給該元件;

如果元件需要改變資料,則父元件傳遞一個改變資料的回調函數給該元件,并在對應事件中調用。

執行個體:點選子元件,改變兄弟元件的字型顔色

export default class SampleTwo extends Component {
    constructor(props) {
        super(props);
        this.state = {
            child1color: 'blue',
        };
    }

    _changeItemColor(color) {
        this.setState({ child1color: color });
    }

    render() {
        return (
            <View style={{flex: 1 }}>
                <Child ref='child1' text='Child one' color={this.state.child1color}/>
                <Child  ref='child2' text='Child two' color='purple'
                    changeBrotherColor={ (color) => this._changeItemColor(color) }/>
            </View>
        );
    }
}

class Child extends Component {

    _changeBrotherColor() {
        this.props.changeBrotherColor && this.props.changeBrotherColor('green');
    }

    render() {
        return (
            <Text style = {{ fontSize: 60, margin: 20, color: this.props.color }}
                onPress={this._changeBrotherColor.bind(this)}>
                {this.props.text}
            </Text>
        );
    }
}
           

3.全局事件

1和2中的方法在組織結構非常深的時候,将會是一個噩夢。我們可以用全局事件來避免這些麻煩

使用事件來實作元件間的溝通:改變資料的元件發起一個事件,使用資料的元件監聽這個事件,在事件處理函數中觸發setState來改變視圖或者做其他的操作。

使用事件實作元件間溝通脫離了單向資料流機制,不用将資料或者回調函數一層一層地傳給子元件。

事件子產品可以使用如EventEmitter或PostalJS這些第三方庫,也可以自己簡單實作一個。

使用RCTDeviceEventEmitter sample code:

import RCTDeviceEventEmitter from 'RCTDeviceEventEmitter';

export default class SampleThree extends Component {
    render() {
        return (
            <View style={styles.container}>
                <ChildInput />
                <ChildShow />
            </View>
        );
    }
}

class ChildInput extends Component {

    handleUpdateChange(text) {
        RCTDeviceEventEmitter.emit('change', text);
    }

    render() {
        return (
            <View style={{ justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF' }}>
                <TextInput onChangeText={(text) => this.handleUpdateChange(text) } style={{ width: 200, height: 40, borderColor: 'gray', borderWidth: 1 }} />
            </View>
        );
    }
}

class ChildShow extends Component {
    constructor(props) {
        super(props);
        this.state = {
            text: '',
        };
    }

    componentDidMount() {
        let me = this;
        RCTDeviceEventEmitter.addListener('change', function (text) {
            me.setState({
                text: text
            })
        })
    }

    render() {
        return (
            <View style={{ justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF' }}>
                <Text>{this.state.text}</Text>
            </View>
        );
    }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
});
           

但是正因為全局事件脫離了單向資料流機制,進而使得資料的流向變得的不可預期。

4. Navigator didfocus 和 Navigator傳遞方法通訊

監聽didfocus事件(不推薦)

用在有Navigator的scenario.

在需要更新資料的元件didmount時重新load storage資料加載

關鍵code

componentWillMount() {
    console.log('componentWillMount');
    let me = this;
    let willcallback = (event) => {
        console.log('will enter ' + this.props.name);
    };

    let didcallback = (event) => {
        console.log(
            'didfocus event ',
            {
                route: event.data.route,
                target: event.target,
                type: event.type
            });

        // homeview did mount
        if ('HomeView' === event.data.route.name && 'didfocus' === event.type) {
            console.log('didfocus HomeView');
            this.updatetext && me.setState({ text: this.updatetext });
        }
    };

    // observe focus change events from this component
    this._listeners = [
        // 該會頁面每次進行切換之前調用
        this._navigator.navigationContext.addListener('willfocus', willcallback),

        // 在每次頁面切換完成或者初始化之後進行調用該方法。該參數為新頁面的路由
        this._navigator.navigationContext.addListener('didfocus', didcallback),
    ];
}
           

Navigator傳遞方法

用在有Navigator的scenario

in SampleFive.js

_navigateToSub() {
    console.log('_navigateToSub');
    const self = this;
    this._navigator && this._navigator.push({
        name: 'SampleFiveSub',
        component: SampleFiveSub,
        params: {
            updateText: (text) => {
                self.updatetext = text;
            }
        }
    });
}

in SampleFileSub.js

_back() {
    console.log('SampleFiveSub _back');
    this.props.updateText && this.props.updateText(this.text)
    const {navigator} = this.props;
    navigator && navigator.pop();
}
           

5. Redux

Redux可以檢視章節 Redux

小結

  • 簡單的的元件溝通可以用傳props和callback的方法實作。随着項目規模的擴大,元件就會嵌套得越來越深,這時候使用這個方法就有點不太适合。
  • 全局事件可以讓元件直接溝通,但頻繁使用事件會讓資料流動變得很亂。
  • 簡單的處理邏輯也可以用Navigator傳遞callback方法
  • 使用redux可以讓你整個項目的資料流向十厘清晰,但是很容易會出現元件嵌套太深的情況,events和context都可以解決這個問題。
  • Transdux是一個類redux架構,使用這個架構可以寫出比redux簡潔的代碼,又可以得到redux的好處。
ReactJS元件間溝通的一些方法