RN电商项目实战——2.组件的State

任何一个复杂的应用,都是由一个简单的应用发展而来的,当应用功能少的时候可能一个组件足够,但是随着功能的增加,把越来越多的功能放到一个组件中就不方便维护管理了。

React Native 组件的数据分为两种,prop(属性,property的缩写) 和 state(状态) ,无论是属性还是状态的改变,都可能引发组件的重新渲染。
所以,一定要记住一个原则,只能由属性或者状态控制界面显示内容的变化,其它的变量绝对不允许控制显示内容的变化。

归结为一个公式,就像下面这样:

UI=render(data)

公式的含义就是用户看到的界面(UI),应该是render()函数执行的结果,只接受数据(data)作为参数。这是一个毫无副作用的函数,data其实就是 prop 和 state ,两次函数如果输入的属性和状态相同,得到的 UI 一定是一样的。

prop 一般用于组件的对外接口,state 是组件的内部状态。

为了演示 prop 和 state 的使用,我们创建一个选择商品数量的组件。如下图所示:

《RN电商项目实战——2.组件的State》

我们在工程目录下创建 src 目录,这个目录和 android/ios 目录平级,用来存放 RN 源码,里面创建一个 component 文件夹用来存放自定义组件。

接下来自定义我们第一个组件 Counter ,工程文件路径:“/src/component/Counter.js”

组件中的 state

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

《RN电商项目实战——2.组件的State》

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

初始化 state

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

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

搭建组件布局文件

组件分为左右各一个按钮,中间是一个输入框。实现代码参照下面代码片段:

    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
        })
    }

参考上面代码片段,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 系统中输入框的下划线。具体参考文档

我们再来看下样式代码,对照着上面代码,里面的组件样式在下面都定义了:

// 样式文件
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
    },
});

读取和更新 state 变量

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 函数才会驱动组件去更新,界面才会重新渲染。于是当我们点击 “+” 或者 “-” 的时候就可以看到界面的变化。

完善输入框

输入框也可以监听输入内容修改状态机变量,修改之前的代码

   <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, 如下图所示,当我们点击的时候并没有明显的影响性能,release版本比测试阶段性能消耗会进一步降低。

《RN电商项目实战——2.组件的State》

查看代码
参考React Native电商项目实战——开篇
示例代码可在 GitHub 上获取 https://github.com/yll2wcf/TShop

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

大家关注我的公众号—— 于连林 公众号ID: likedev,回复RN 即可查看视频地址。视频每周都会更新,大家保持关注。

读者讨论群

对内容,代码有疑问的读者,可以加入讨论群:274328657 交流,加群务必备注:RN学习。

请大家关注我的简书文集——React Native 电商项目实战 教程都会在这里更新。

    原文作者:于连林520wcf
    原文地址: https://www.jianshu.com/p/6a2ca293fce5
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞