Day2:react组件初探

98 阅读5分钟

本文为书籍《深入浅出React和Redux》的笔记 书中React的版本为v15.4,学习时React的版本为v17.0.2 文中提到的ControlPanel.js为父组件,Counter.js为子组件

书中提到的代码下载来源

github.com/mocheng/rea…

作为一个合格的开发者,不要只满足于编写出了可以运行的代码,而要了解代码背后的工作原理;不要只满足于自己编写的程序能够运行,还要让自己的代码可读而且易于维护。这样才能开发出高质量的软件。

易于维护组件的设计要素

高内聚:指的是把逻辑紧密相关的内容放在一个组件中。 低耦合:指的是不同组件之间的依赖关系要尽量弱化,也就是每个组件要尽量独立。

React组件的数据分为两种

prop和state,无论prop或者state的改变,都可能引发组件的重新渲染,prop是组件的对外接口,state是组件的内部状态,对外用prop,内部用state。

【解决BUG】 在尝试第二个案例的时候报错了

ERROR in ./src/Counter.js 97:11-38

export 'PropTypes' (imported as 'PropTypes') was not found in 
'react' (possible exports: Children, Component, Fragment, 
Profiler, PureComponent, StrictMode, Suspense, 
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, 
cloneElement, createContext, createElement, createFactory, 
createRef, forwardRef, isValidElement, lazy, memo, useCallback,
 useContext, useDebugValue, useEffect, useImperativeHandle, 
 useLayoutEffect, useMemo, useReducer, useRef, useState, 
 version)

搞了半天,最后还是通过搜索解决了,应该是代码太旧的问题

import React, { Component, PropTypes } from 'react';

把以上代码改为

import React, { Component } from 'react';
import PropTypes from 'prop-types';

【注意】 提前 npm install --save prop-types 此外还要检查其它文件是否有类似问题,都要改

解决链接是:stackoverflow.com/questions/4…

React的prop

在React中,prop(property的简写)是从外部传递给组件的数据,一个React组件通过定义自己能够接受的prop就定义了自己的对外公共接口。

每个React组件都是独立存在的模块,组件之外的一切都是外部世界,外部世界就是通过prop来和组件对话的。

React组件的prop所能支持的类型则丰富得多,除了字符串,可以是任何一种JavaScript语言支持的数据类型。

当prop的类型不是字符串类型时,在JSX中必须用花括号{}把prop值包住,所以style的值有两层花括号,外层花括号代表是JSX的语法,内层的花括号代表这是一个对象常量。如下

给prop(property)赋值

【注意】 React要求render函数只能返回一个元素。

<SampleButton
  id="sample"
 borderWidth={2} onClick={onButtonClick}  style={{color: "red"}}/>

部分示例代码:父组件ControlPanel用prop传递信息给Counter子组件

class ControlPanel extends Component {
  render() {    
  return (      
      <div>        
      <Counter caption="First" initValue={0} />        
      <Counter caption="Second" initValue={10} />
      <Counter caption="Third" initValue={20} />      
      </div>    
      //通过名为caption的prop,ControlPanel传递给Counter组件实例说明文字。
      //通过名为initValue的prop传递给Counter组件一个初始的计数值。
      );  
  }}

读取prop值

来看Counter组件内部是如何接收传入的prop的

【名词解释】构造函数:是一种特殊的方法。 主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。

首先是构造函数,代码如下:

class Counter extends Component {
  constructor(props) {    
  super(props); 
  如果一个组件需要定义自己的构造函数,
  一定要记得在构造函数的第一行通过super调用父类也
  就是React.Component的构造函数。
  this.onClickIncrementButton =
 this.onClickIncrementButton.bind(this);    
 this.onClickDecrementButton =
 this.onClickDecrementButton.bind(this);    
 this.state = {      
 count: props.initValue || 0
 // 在构造函数中可以通过参数props获得传入prop值
 // 在其他函数中则可以通过this.props访问传入prop的值,
    }  
}

propTypes检查

既然prop是组件的对外接口,那么就应该有某种方式让组件声明自己的接口规范。简单说,一个组件应该可以规范以下这些方面:

  1. 这个组件支持哪些prop;
  2. 每个prop应该是什么样的格式。

React通过propTypes来支持这些功能 比如,对于Counter组件的propTypes定义代码如下:

Counter.propTypes = {
  caption: PropTypes.string.isRequired,  
  //要求caption必须是string类型
  //caption带上了isRequried,这表示使用Counter组件必须要指定caption
  initValue: PropTypes.number
  //initValue必须是number类型。
  };

【注意】 propTypes检查只是一个辅助开发的功能,并不会改变组件的行为。即使在上面propTypes检查出错的情况下,组件依旧能工作。

propTypes虽然能够在开发阶段发现代码中的问题,但是放在产品环境中就不大合适了。babel-react-optimize可以将其在生产环境去掉

React的state

驱动组件渲染过程的除了prop,还有state,state代表组件的内部状态。由于React组件不能修改传入的prop,所以需要记录自身数据变化,就要使用state。

组件的state必须是一个JavaScript对象,不能是string或者number这样的简单数据类型

初始化state

通常在组件类的构造函数结尾处初始化state

constructor(props) {
  …  this.state = {    count: props.initValue || 0  
  //如果没有,就使用默认值0。
}}

初始值可能被遗漏,那我们会给一个默认的初始值,但是如果默认的初始值被遗漏怎么办,而且一直这样写代码也不美观,那我们可以用React的defaultProps功能,让代码更加容易读懂。

Counter.defaultProps = {
  initValue: 0
  };
  //上述代码写在组件最后
  
  //这样上面的代码就可以简化成:
  count: props.initValue
  //,即使Counter的使用者没有指定initValue,
  在组件中就会收到一个默认的属性值0

读取和更新state

不要直接修改state,应该使用 setState(),直接修改无法触发渲染,只会改变值,这样页面上就无法看到改变

 onClickIncrementButton() {
    this.setState({count: this.state.count + 1});
  }

prop和state的对比

在这里插入图片描述

【注意】 组件是绝不应该去修改传入的props值的。