美文网首页
React Navite踩坑日记)(四) —— 组件间传值 ——

React Navite踩坑日记)(四) —— 组件间传值 ——

作者: 黑羽肃霜 | 来源:发表于2017-08-22 21:24 被阅读66次
安卓模拟器上的示意图

这里截取一个安卓模拟器的页面来说明。

实际要解决的问题

  • iOS为例
    不同于我们iOS开发,假设我们现在用OC来实现一个上图中的页面,通常要做的是在两个textField输入框中获取用户的输入信息,而这两个textField也是整个viewControllerproperty属性变量。
    我们在点击下方的注册按钮时,用正则去判断输入的合法性。
    —— 一切都这么自然

  • RN面临的问题
    我们新建工程后,RN很自然的将整个页面作为一个总的父组件。然后根据页面中的布局,实际上是有三个子组件,分别是

    • 顶部的码上公交背景图 —— 姑且成为 Top组件
    • 中间的输入区域 —— 分为电话号码输入; 验证码输入。 —— 称为A组件
    • 底部的登录/注册按钮。 —— 称为B组件

    中部的按钮中 TextInput组件根据state在B组件的内部获取用户的输入信息。那么就带来了一个问题,当我在C组件中按下登录时,C组件中并没有持有B组件中的输入框内容,要怎么办?
    —— 解决方式,就是我们要说的组件间传值。

解决方案 —— 组见间传值

先看下面两篇关于组件间传值的参考文章(筛选了比较久)
组件间传值参考文章一
组件间传值参考文章二

在熟悉propsstate的基础上,继续下面的内容。

解决方案一

child component B中的输入内容,通过props对应的回调函数,传给parent component父组件。

通俗的理解,就是在父组件中,用一个state持有两个输入框的文本内容。而这两个状态机变量,和子组件中是类似的。而后在子组件中根据回调函数通知父组件修改。而后直接在组件C按下时,调用父组件内的合法性输入判断函数。

// 父组件中包含子组件时,将回调函数传给props
constructor(props){
  super(props);
  this.state = {
      phoneNum:'',
      veriCode:'',
  }
}
changePhoneNum(num){
  this.setState({phoneNum:num});
}
<ChildComponentB onEndInput={this.changePhoneNum.bind(this)} />

解决方案二

在组件B和组件C之间作平级的组件传值,这里就要引入JS中的消息广播机制,DeviceEventEmitter

在B组件完成输入后,调用消息发送的广播。而后在C组件中增加两个监听,分别监听输入的电话号码输入的验证码. 唯一需要担心和不大了解的是,JS中使用消息通信机制,是否和OC中使用广播一样,虽然去耦,但是比较耗资源。


以下,是完整的代码,供参考

/**
 * Created by Defore on 2017/8/16.
 */
import React, {Component} from 'react';
import {
    StyleSheet,
    Text,
    View,
    Dimensions,
    TouchableOpacity,
    TextInput,
    Platform,
    Image,
    Button,
    DeviceEventEmitter,
} from 'react-native';
import baseStyle from '../BaseStyles'

const {width, height} = Dimensions.get('window');

const loginBgIco = require('../srcImg/Login/login_bg.png');//750*350
const phoneIco = require('../srcImg/Login/num_default.png');//28*44
const phoneSelIco = require('../srcImg/Login/num_selected.png');//48*44

const veriCodeIco = require('../srcImg/Login/code_default.png');//44*44
const veriCodeSelIco = require('../srcImg/Login/code_selected.png');//44*44

const busBgIco = require('../srcImg/首页/index_bg.png');//466*246

export default class Login extends Component {
    constructor(props) {
        super(props);
        this.state = {
            phoneNum: '',
            veriCode: '',
        };
    }

    static navigationOptions = {
        header: null,
    };

    render() {
        return (
            <View style={styles.container}>
                <Image style={{width: width, height: 169 / 667 * height,}} source={loginBgIco}/>
                <PhoneNoInput />
                <View style={{width: width - 42, height: 1, backgroundColor: '#E6E6E6',}}/>
                <VeriCodeInput />
                <LoginBtnArea />
            </View>
        );
    }
}


/*  登录 - 输入手机号 */
class PhoneNoInput extends Component {
    constructor(props) {
        super(props);
        this.state = {
            phoneImg: phoneIco,
            phoneNumber: '',
        };
    }

    // 若输入为空,就恢复成默认
    checkWhetherEmptyInput() {
        if (this.state.phoneNumber.length === 0) {
            this.setState({phoneImg: phoneIco});
        } else {
            DeviceEventEmitter.emit('phone', this.state.phoneNumber);
        }
    }

    render() {
        return (
            <View style={styles.inputView}>
                <View style={styles.icoContainterView}>
                    <Image style={{width: 13.5, height: 22}} source={this.state.phoneImg}/>
                </View>
                <TextInput style={[baseStyle.regularFont, styles.phoneNoInput]} underlineColorAndroid={'transparent'}
                           placeholder={'请输入手机号'} placeholderTextColor={'#D5D5D5'}
                           keyboardType={Platform.OS === 'ios' ? 'number-pad' : 'numeric'}
                           returnKeyType={'done'}
                           onFocus={() => {
                               this.setState({phoneImg: phoneSelIco})
                           }}
                           onEndEditing={() => {
                               this.checkWhetherEmptyInput();
                           }}
                           onChangeText={(input) => {
                               this.setState({phoneNumber: input});
                               // DeviceEventEmitter.emit('phone', input);
                           }}
                />
            </View>
        )
    }
}

/*  登录 - 输入验证码 */
class VeriCodeInput extends Component {
    constructor(props) {
        super(props);
        this.state = {
            veriCodeImg: veriCodeIco,
            veriCode: '',
        };
    }

    // 若输入为空,就恢复成默认
    checkWhetherEmptyInput() {
        if (this.state.veriCode.length === 0) {
            this.setState({veriCodeImg: veriCodeIco});
        } else
            DeviceEventEmitter.emit('vericode', this.state.veriCode);
    }

    render() {
        return (
            <View style={styles.inputView}>
                <View style={styles.icoContainterView}>
                    <Image style={{width: 22, height: 22}} source={this.state.veriCodeImg}/>
                </View>
                <TextInput style={[baseStyle.regularFont, styles.veriCodeInput]} underlineColorAndroid={'transparent'}
                           placeholder={'请输入验证码'} placeholderTextColor={'#D5D5D5'}
                           keyboardType={Platform.OS === 'ios' ? 'number-pad' : 'numeric'}
                           returnKeyType={'done'}
                           onFocus={() => {
                               this.setState({veriCodeImg: veriCodeSelIco})
                           }}
                           onEndEditing={() => {
                               this.checkWhetherEmptyInput()
                           }}
                           onChangeText={(input) => {
                               this.setState({veriCode: input});
                               // DeviceEventEmitter.emit('vericode', input);
                           }}
                />
                <View style={{width: 1, height: 34 / 667 * height, backgroundColor: '#D9D9D9',}}/>
            </View>
        )
    }
}

/*-----------------  登录按键 -----------------*/
class LoginBtnArea extends Component {
    constructor(props) {
        super(props);
        this.state = {
            phoneNum: '',
            veriCode: '',
        };
    }

    componentDidMount() {
        //添加收听者,监听 电话号码/验证码时
        this.phoneInputListen = DeviceEventEmitter.addListener('phone', (phoneNum) => {
            console.log('收听到电话--?');
            this.setState({phoneNum: phoneNum})
        });

        this.veriInputListen = DeviceEventEmitter.addListener('vericode', (code) => {
            console.log('收听到验证码==');
            this.setState({veriCode: code})
        });

    }

    componentWillUnmount() {
        this.phoneInputListen.remove();
        this.veriInputListen.remove();
    }

    judgeLegalInput() {
        console.log('电话号码' + this.state.phoneNum + '\n');
        console.log('验证码' + this.state.veriCode + '\n');
    }

    render() {
        return (
            <TouchableOpacity style={styles.loginBtnArea} onPress={this.judgeLegalInput.bind(this)}>
                <Text style={[baseStyle.regularFont, {fontSize: 16, color: 'white'}]}>注册/登录</Text>
            </TouchableOpacity>
        )
    }
}

//---------------------------------------------
const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'flex-start', alignItems: 'center',
        backgroundColor: '#ffffff',
    },
    /* --------- 手机号输入 ---------*/
    icoContainterView: {
        width: 63, height: 61,
        justifyContent: 'center', alignItems: 'center',
    },

    inputView: {
        flexDirection: 'row',//从左往右
        justifyContent: 'flex-start', alignItems: 'center',
        height: 61, width: width,
    },
    phoneNoInput: {
        fontSize: 16, color: '#76ABF1',
        width: width - 63 - 20, height: 61,
    },
    /* --------- 验证码输入 ---------*/
    veriCodeInput: {
        fontSize: 16, color: '#76ABF1',
        width: 182 / 375 * width, height: 61,//backgroundColor:'red',
    },

    /* --------- 登录按键 ---------*/
    loginBtnArea: {
        justifyContent: 'center', alignItems: 'center', marginTop: 155 /667* height ,
        width: width - 40, height: 50, backgroundColor: '#A8CE47',
    }
});

相关文章

  • React Navite踩坑日记)(四) —— 组件间传值 ——

    这里截取一个安卓模拟器的页面来说明。 实际要解决的问题 以iOS为例不同于我们iOS开发,假设我们现在用OC来实现...

  • react子组件向父组件传值

    相关资料:react 父组件怎么获取子组件的这个值React组件间信息传递方式react同级组件之间传值 • 父...

  • react-父子组件间通信

    React-父子组件间通信 父组件传 值 给子组件, 传 方法 给子组件 子组件接收 值 ,触发父组件的 方法

  • Vue和React组件通信的总结

    在现代的三大框架中,其中两个Vue和React框架,组件间传值方式有哪些? 组件间的传值方式 组件的传值场景无外乎...

  • React Navite踩坑日记)(五) —— FlatList

    参考文章 一个韩国人讲的FlatList视频(请忽略口音) 参考文章 理解 同样类比于我们iOS的TableVie...

  • react组件间传值

  • (React)组件间传值

    前言 有了自定义组件,当然也会有组件间的传值 一、父组件向子组件传值 父组件向子组件传值的时候,使用属性传递的方式...

  • uni组件传值注意

    目录介绍 01.组件传值遇到坑 02.父组件传值给子组件 03.子组件传值给父组件 01.组件传值遇到坑 子组件给...

  • 组件基础

    组件的入门 组件的私有化 组件的切换 组件间的传值-向组件内传值 组件间传值-向组件外传值 ref获取元素

  • React父子组件间的传值的方法

    在单页面里面,父子组件传值是比较常见的,这篇文章主要介绍了React父子组件间的传值的方法,小编觉得挺不错的,现在...

网友评论

      本文标题:React Navite踩坑日记)(四) —— 组件间传值 ——

      本文链接:https://www.haomeiwen.com/subject/znhrdxtx.html