React的元素、组件与事件处理
徐徐 抱歉选手

HTML DOM结点与React DOM

一个HTML DOM结点对于React来说是“根”DOM结点,关于该节点的所有内容都由React DOM管理。

.js文件中利用React语法生成各种元素、组件,而后通过ReactDOM.render(待渲染的元素或组件, 利用普通DOM获得HTML中的节点)渲染到HTML中对应的根DOM节点中。

利用React DOM的优点是它只将元素和它的子元素与它们之前的状态比较,只进行必要的更新来达到预期状态。

元素

React元素既可以是原HTML文件中的DOM标签及其组合,也可以是用户自定义的组件。

const element = DOM-tag-or-self-defined-component

组件

组件名称必须大写字母开头。

一般组件

函数组件:本质是编写JavaScript函数。

1
2
3
function Toppercase(props){
return React-element;
}

class组件

1
2
3
4
5
class Toppercase extends React.Component{
render(){
return React-element;
}
}

组合组件

(更高一层级/更偏向用户层的)组件可以在其输出中引用其他(更低一层级/实现功能更单一的)组件。

一般来说,每个新的React应用程序的顶层组件都是App组件。

如何抽取组件

元素的声明可以包含不止一个HTML结点(当然这是被允许的JSX写法),将元素抽取出来利用组件重新声明。

在被抽取出来的部分需要利用props对象在组件内部访问组件本身的属性、子组件及其属性;在更高层次的组件内部使用较低层次的组件,使用大写的单闭合的标签来标明属性及其取值。

这是属于外观的封装。

组件内部属性访问

props

当React元素为用户自定义组件时,它会将JSX所接收的属性attributes以及子组件children转换为单个对象传递给组件,这个对象被称为props

要在更高层级更抽象的组件层次访问更低层次更具体的组件层次,需要使用点访问,props.children.child-attributeprops.attribute

props具有只读性,组件不能修改自身的props。因为这是静态的,不可更改的,后面需要在组件中引入state来实现组件自我更新。

state

1、只能在构造函数中对this.state=使用赋值语句。

2、为了达成更改state且重新渲染组件的目的,需要使用setState()

3、this.statethis.props的更新可能是异步的,不要利用这两个值来更新下一个状态。应当将他们作为函数的参数传入,在函数体内更新。

4、 当state包含多个属性时,单独更新其中某一个属性的值时,setState()会自动将更新的state合并到当前没有更改的state。

state与props的关系

自上而下的单项数据流决定了:

任何state只属于拥有并设置了它的组件,是局部的、封装的。

某一组件可以将state作为props向下传递给它的子组件。

将函数组件转换成class组件

为什么需要从函数组件转换到class组件

每次组件更新时都有实例中的render()被调用。

ReactDOM渲染DOM节点的时候,只有一个此组件的实例被创建,关于这个实例可以使用state或生命周期方法。

步骤

1、同名class且继承与React.Component

2、类体添加render()方法并将函数体放入其中

3、函数体中的this.props替换props

4、删除剩余的空函数声明

在class组件中添加并使用state

1、将需要做出变化的属性从props的点访问转移到state的点访问。

2、添加class构造函数,为this.state赋初始值,且通过super(props)传递到父类的构造函数中。

在class组件中添加并使用生命周期方法

目的是在组件被销毁时释放资源。

当组件第一次被渲染到DOM的时候,设置一个“挂载”(mount)。componentDidMount(){}

当组件被删除的时候,设置一个“卸载”(unmount)。componentWillUnmount(){}

class组件关于state和生命周期的调用顺序

组件被传递给ReactDOM.render(),对应到匹配的根节点DOM,进入组件。

React会调用该组件的构造函数,对象初始化。

React会调用该组件的render()方法,确定在html页面上要展示什么,更新根节点DOM来匹配组件输出。

一旦组件的初始输出被插入到根节点DOM中后,React调用组件中挂载的生命周期方法。

生命周期方法或其调用的其他方法会涉及setstate()方法,由此React知道了state已经改变,重新调用render()确定页面显示内容,从而渲染更新根节点DOM。

一旦组件从DOM中被移除,React调用卸载的生命周期方法。

列表组件与key

在一个组件中渲染列表,通常可以对数组进行调用arr.map( arrow-function)。箭头函数执行将数组转化为列表元素(list item)的功能。

当我们创建一个列表元素(list item)时,我们必须给每一个列表元素指定一个key属性,即<li key={}> {JS-expression} </li>

key

key 帮助 React 识别哪些元素改变了,比如被添加或删除。

key是传递给React的,而不是传递给组件的,即不能用props.key来获取key属性的值。可以另外引入一个别名属性如id,其属性值与key属性值相同,可以被组件利用props.id读出。

一般使用数据中的id(data.id)来作为元素的key,不到万不得已使用元素索引。

key不一定要全局唯一,但是在其兄弟节点之间独一无二。

当把单个列表元素作为函数组件提取出来的时候,应该在哪里设置key?经验总是:在map()方法中的元素设置key。

受控组件与表单

为什么需要受控组件

HTML表单元素的工作方式与其他DOM元素不一样。表单元素如<input><textarea><select>通常会维护一个属于自己的“state”,根据用户输入自动进行UI上的更新。

React中,组件的state属性控制着可变状态(mutable state),并且只能通过setState()来更新。

需要让这两个state建立依赖关系统一起来——让React组件的state称为唯一的数据源,并让组件能够控制用户输入过程中表单发生的操作。

被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

受控组件的建立

分为两个步骤

1、 将React里的state属性和表单元素的值建立依赖关系。

也就是让组件获得对表单元素输入框内容的控制权。输入框的内容取决于元素的value属性,将表单元素的value属性赋值为this.state.value-of-element

此时,表单元素内容是只读的,用户输入新的内容并不会让组件的state有所变化。此时运行会给出警告:

Warning: Failed prop type: You provided a value prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultValue. Otherwise, set either onChange or readOnly.

2、 通过onChange事件与setState()结合更新state属性

用一个事件来监听输入内容的改变,在回调函数中利用this.setState更新表单元素的value属性。

组件间的数据共享

多个组件需要反应相同的数据变化时,需要把共享状态提升到共同父组件中去,让父组件中共享的state称为多个子组件的唯一的数据源。实现自上而下的数据流

一般在一个组件内部变化的数据通过state来访问或控制,多个组件在个字内部的state中相互独立地保存着各自的数据。

操作步骤

第一步,需要夺取子组件对共享数据的控制权,包括初始赋值与变化赋值。其思想与受控组件相同。

将想要共享的数据从由子组件内部state访问变成由父组件props传入,即由this.state.shared-data变为this.props.shared-data

当我们需要子组件相应来自父组件的数据改变时,不再使用this.setState(),而是调用this.props.shared-data-change-function,获取父组件中具体的值,这个值就是一个事件处理函数。

第二步,相应改变父组件。

需要在父组件中构造函数中把this.state设置为想要共享的数据。

在父组件中提供子组件相应数据更改的函数,并作为属性值传入子组件中。

组合

空元素

空元素(empty element)是在HTML中不能存在子节点(例如内嵌的元素或者元素内的文本)的element。

一般的HTML元素的名称是在尖括号中使用的小写名称。例如,<p><\p>带有一个斜杠开始的结束标记

在一个空元素上结束标记既不需要也不允许,使用闭合标签是无效的。<input><\input>是无效的写法,应该使用<input \>

组件使用的约定

在组件使用中我们需要注意两点:

1、 必须大写字母开头。这是为了和一般的HTML元素的小写名称加以区别

2、 在使用时没有闭合标签。这样的组件就与之前提到的空元素类似。

第二个注意点不一定是完全成立。当我在组件中包含/嵌套子组件,可以通过带闭合标签的尖括号将子组件传递给组合组件。由此引入组合、props.children的概念。

组合与props

方式1:

在组件定义中引入{props.children}

在组件使用时传入<Component>your-children-Component<\Component>

方式2:

在组件定义中引入{props.self-defined-attribute}

在组件使用时传入<Component self-defiend-attribute={sub-Component}\>

  • 本文标题:React的元素、组件与事件处理
  • 本文作者:徐徐
  • 创建时间:2020-10-05 21:37:31
  • 本文链接:https://machacroissant.github.io/2020/10/05/react-learning/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论