React Native 系列,五 -- 组件间传值

前言

本系列是基于React Native版本号0.44.3写的。任何一款 App 都有界面之间数据传递的这个步骤的,那么在RN中,组件间是怎么传值的呢?这篇文章将介绍到顺传、逆传已经通过通知传值。

顺传

其实我们在本系列第二篇文章中,讲述PropsState的时候就已经接触了顺传。

  • 通过props传值

    举个????:父控件给子控件传递一个name属性的值,子控件展示父控件传递过来的值:

    // 子组件
    class SonComponent extends Component {
        render(){
            return (
                <View style={styles.sonViewStyle}>
                    <Text style={{fontSize: 20}}>这是父视图传递过来的数据:{this.props.name}</Text>
                </View>
            );
        }
    }
    
    // 父组件
    class FatherComponent extends Component {
        render(){
            return (
                <View style={styles.container}>
                    <SonComponent name={this.props.name}/>
                </View>
            );
        }
    }
    
    // 主组件
    export default class RNDemoOne extends Component {
        render() {
            return (
                <View style={styles.container}>
                    <FatherComponent name="scott"/>
                </View>
            );
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flex: 1,
            backgroundColor: 'red',
        },
    
        sonViewStyle: {
            flex: 1,
            backgroundColor: '#F5FCFF',
            justifyContent: 'center',
            alignItems: 'center',
        },
    });
    

    上述代码的数据传递其实是这样的: 主组件 -> FatherComponent -> SonComponent。

    但是有时候,我们并不是在创建 子组件 的时候就传递值,而是需要等待某个触发事件的时候,再传递,这就涉及到获取子组件传值。

  • 通过ref拿到组件,然后传值

    举个????:通过点击屏幕上的 + 号按钮,实现没点击一次,让SonComponent的输出数字加1。

    // 子组件
    class SonComponent extends Component {
    
        // 构造
        constructor(props) {
            super(props);
            // 初始状态
            this.state = {
                number: 1
            };
        }
    
        addClick(number){
            this.setState({
                number: number
            });
        }
    
        render(){
            return (
                <View style={styles.sonViewStyle}>
                    <Text style={{fontSize: 20}}>{this.state.number}</Text>
                </View>
            );
        }
    }
    
    // 父组件
    class FatherComponent extends Component {
        render(){
            return (
                <View style={styles.container}>
                    <SonComponent ref="son" number={this.props.number}/>
    
                    <View style={styles.fatherViewStyle}>
                        <Text style={{fontSize: 40}} onPress={() => {
                                                                    this.refs.son.addClick(this.refs.son.state.number + 1)
                    }}>{"+"}</Text>
                    </View>
                </View>
            );
        }
    }
    
    // 主组件
    export default class RNDemoOne extends Component {
        render() {
            return (
                <View style={styles.container}>
                    <FatherComponent number={1}/>
                </View>
            );
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flex: 1,
        },
    
        sonViewStyle: {
            flex: 1,
            backgroundColor: '#F5FCFF',
            justifyContent: 'center',
            alignItems: 'center',
        },
    
        fatherViewStyle: {
            flex: 1,
            justifyContent: 'center',
            alignItems:'center',
        },
    });
    

逆传

  • 使用方法回调:

    1. 在父组件定义一个处理接收值的方法
    2. 把这个方法传递给子组件,并且绑定this,子组件就能通过this.props拿到这个方法调用

举个例子,同样是点击屏幕上的 + ,让屏幕上的数字 加 1。(ps:和上面通过ref拿到子组件,传递的代码有区别,注意组件层级)

// 子组件
class SonComponent extends Component {
    addClick(){
        this.props.receiveNumber()
    }

    render(){
        return (
            <View style={styles.sonViewStyle}>
                    <Text +"}</Text>
            </View>
        );
    }
}

// 父组件
class FatherComponent extends Component {

    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        this.state = {
            number: 1
        };
    }

    receiveNumber(){
        var m = this.state.number;
        m += 1;
        this.setState({
            number: m
        });
    }

    render(){
        return (
            <View style={styles.container}>
                <SonComponent receiveNumber={this.receiveNumber.bind(this)}/>

                <View style={styles.fatherViewStyle}>
                    <Text style={{fontSize: 20}}>{this.state.number}</Text>
                </View>
            </View>
        );
    }
}

// 主组件
export default class RNDemoOne extends Component {
  render() {
    return (
        <View style={styles.container}>
            <FatherComponent/>
        </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
      flex: 1,
  },

    sonViewStyle: {
        flex: 1,
        backgroundColor: '#F5FCFF',
        justifyContent: 'center',
        alignItems: 'center',
    },

    fatherViewStyle: {
        flex: 1,
        justifyContent: 'center',
        alignItems:'center',
    },
});

通知

  • 当两个组件之间互相拿不到谁的时候,可以用通知传值。比如当两个组件是同一层级关系的时候(兄弟关系)。

举个????: 点击发送生活费,哥哥就给弟弟发送100生活费。

// 弟弟组件
class DiDiComponent extends Component {

    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        this.state = {
            money: 0
        };
    }

    componentDidMount() {
        // 添加监听者
        this.listener = DeviceEventEmitter.addListener('makeMoney', (money) => {
            this.setState({
                money: money
            });
        })
    }

    componentWillUnmount() {
        // 销毁监听者
        this.listener.remove();
    }

    render(){
        return (
            <View style={styles.didiStyle}>
                <Text>弟弟</Text>
                <Text>收到{this.state.money}零花钱</Text>
            </View>
        );
    }
}

// 哥哥组件
class GeGeComponent extends Component {

    render(){
        return (
            <View style={styles.gegeStyle}>
                <Text>哥哥</Text>
                <Text onPress={()=>{
                    DeviceEventEmitter.emit('makeMoney', 100)
                }}>发生活费</Text>
            </View>
        );
    }
}

// 主组件
export default class RNDemoOne extends Component {
  render() {
    return (
        <View style={styles.container}>
            <DiDiComponent/>
            <GeGeComponent/>
        </View>
    );
  }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },

    didiStyle: {
        flex: 1,
        backgroundColor: '#F5FCFF',
        justifyContent: 'center',
        alignItems: 'center',
    },

    gegeStyle: {
        flex: 1,
        justifyContent: 'center',
        alignItems:'center',
    },
});

点击发送生活费,就可以看到弟弟能接收到生活费。

好了,组件间传值就讲到这里了。

致谢

如果发现有错误的地方,欢迎各位指出,谢谢!