2.1.1 组件中的 state

组件内部进行渲染主要由 state 控制,RN 中记录组件自身数据变化,必须用 state。

图2-2 计数控件

设计 Counter 组件显示内容如图2-2 所示,我们可以点击 “+” 和 “-” 按钮改变这个计数,这个变化的数据就要通过 state 控制。

1.初始化 state

通常在组件类的构造函数结尾处初始化 state,在 Counter 构造函数中,通过对 this.state 的赋值完成了对组件 state 的初始化,参考代码片段2-1-1。

export default class Counter extends Component {
    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        this.state = {
            value: 1
        };
    }
    // ...
}

代码片段2-1-1

2.搭建组件布局文件

参考图2-2 ,组件分为左右各一个按钮,中间是一个输入框。实现代码参照代码片段2-1-2。

    render() {
        return ( // 渲染布局
            <View style={styles.operatingBox}>
                <TouchableOpacity activeOpacity={0.2}
                                  style={styles.reduce}
                                  onPress={this._reduce.bind(this)}>
                        <Text allowFontScaling={false} style={[styles.btn1]}>-</Text>
                </TouchableOpacity>
                <View style={styles.inpBox}>
                    <TextInput style={styles.inp1}
                               value={this.state.value.toString()}
                               autoFocus={false}
                               underlineColorAndroid="transparent">
                    </TextInput>
                </View>
                <TouchableOpacity activeOpacity={0.2}
                                  style={styles.plus}
                                  onPress={this._plus.bind(this)}>
                        <Text allowFontScaling={false} style={[styles.btn1]}>+</Text>
                </TouchableOpacity>
            </View>
        );
    }

    _reduce() {
        this.setState({
            value: this.state.value - 1
        })
    }
    _plus() {
        this.setState({
            value: this.state.value + 1
        })
    }

代码片段2-1-2

参考代码片段,TouchableOpacity 控件按下时有高亮显示,是通用的处理按下效果的组件。

TouchableOpacity 之外还有 TouchableNativeFeedback 类似组件比较常用,该遵循 Android 质感设计,体验比较好,只不过这个组件只适用于 Android 21版本以上。

有时候我们需要在 Android 21版本上使用 TouchableNativeFeedback,在 iOS 和 Android 低版本上使用 TouchableOpacity。你如果嫌麻烦,可以使用第三方组件 react-native-platform-touchable 地址:https://github.com/react-community/react-native-platform-touchable

TouchableNativeFeedback 只能包裹一个子组件,所以我们有时候为了替换方便,写 TouchableOpacity 时也只包裹一个子组件,所以写完了 TouchableOpacity 然后在里面再定义一个相对多余的 View 当容器并不是什么坏习惯。比如前面的代码可以改成:

<TouchableOpacity activeOpacity={0.2}
                  onPress={this._reduce.bind(this)}>
     <View style={styles.reduce}>
          <Text allowFontScaling={false} style={[styles.btn1]}>-</Text>
      </View>
</TouchableOpacity>

文本控件 Text allowFontScaling={false} 表示不允许控件跟随手机字体大小变化。

TextInput 是输入框组件,underlineColorAndroid="transparent" 是去掉 Android 系统中输入框的下划线。具体参考文档: http://facebook.github.io/react-native/docs/textinput.html

我们再来看下样式代码,对照着代码片段2-1-2,里面的组件样式都代码2-1-3中定义了:

// 样式文件
const styles = StyleSheet.create({
    operatingBox: {
        width: 120,
        height: 35,
        borderColor: '#ddd', // 边框颜色
        borderWidth: 1,
        flexDirection: 'row',//横向布局
        alignItems: 'center',
        borderRadius: 5, //圆角半径
        overflow: 'hidden' // 超出控件范围的隐藏
    },
    btn1: {
        fontSize: 18,
        textAlign: 'center',
        backgroundColor: 'transparent'
    },
    inpBox: {
        flex: 1,
        borderRightWidth: 1,
        borderRightColor: '#ddd',
    },
    reduce: {
        width: 34,
        height: 34,
        justifyContent: 'center',
        borderRightWidth: 1,
        borderRightColor: '#ddd',
    },
    plus: {
        width: 34,
        height: 34,
        justifyContent: 'center'
    },
    inp1: {
        flex: 1,
        backgroundColor: 'transparent',
        textAlign: 'center', 
        padding: 0, 
        fontSize: 14
    },
});

代码片段2-1-3

读取和更新 state 变量

参考代码片段2-1-2 ,TextInput 组件中的 value 属性定义了输入框的内容,在这里用状态机变量控制显示, this.state.value.toString()

TouchableOpacity 组件通过 onPress 绑定了按钮的回调方法,onPress={this._reduce.bind(this)} 这里记得对方法进行绑定操作,否则在方法里无法使用 this 变量。

_reduce()_plus() 方法分别通过 this.setState 函数修改了状态机变量的值。

在代码中,通过 this.state 可以读取到组件的当前 state 。 值得注意的是,我们改变组件 state 必须要使用 this.setState 函数,而不能直接去修改 this.state。 当调用this.setState 函数才会驱动组件去更新,界面才会重新渲染。于是当我们点击 “+” 或者 “-” 的时候就可以看到界面的变化。

完善输入框

输入框也可以监听输入内容修改状态机变量,修改代码片段2-2 中的代码

   <TextInput style={styles.inp1}
              returnKeyType='done'
              maxLength={3}
              onEndEditing={this._checkNumber.bind(this)}
              value={this.state.value.toString()}
              keyboardType="numeric"
              onChangeText={(txt) => this.setState({value:Number(txt)})}
              autoFocus={false}
              underlineColorAndroid="transparent">
    </TextInput>
  • keyboardType 约束了软键盘类型,numeric 是数字类型键盘
  • returnKeyType 添加了完成的返回按钮
  • onChangeText 文本输入框变化的时候回调改方法,在这里修改了状态机变量
  • onEndEditing 输入完成的时候回调方法,调用了下面的 _checkNumber 方法。里面对输入内容做了处理,不允许 value 小于 1,并修改了状态机变量。
    _checkNumber(){
        let value=this.state.value;
        if(value===''||value<1){
            value=1;
        }else{
            value=Math.floor(value); //舍去小数
        }
        this.setState({value:value})
    }

虽然每次 setState 每次都刷新界面,大家不用考虑性能的问题,RN 框架都已经处理了。 查看性能方式;

  • Android模拟器 Ctrl/Command + M
  • iOS 模拟器 Command + D

调出调试菜单,点击 Show Perf Monitor, 如图2-3所示,当我们点击的时候并没有明显的影响性能,release版本比测试阶段性能消耗会进一步降低。

图2-3查看性能

查看代码

如果你已经从 GitHub 上克隆了这个程序的 Git 仓库,那么可以执行 git checkout 2a签出程序的这个版本。

results matching ""

    No results matching ""