React笔记1
Posted demystify
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React笔记1相关的知识,希望对你有一定的参考价值。
一、准备知识
ES6、JSX
二. 组件
定义组件的两种方式:使用ES 3 class(类组件)和使用函数(函数组件)
-
使用class定义组件:
- class 继承自React.component
- class内部必须定义render方法,render方法返回代表该组件UI的元素;
-
使用函数定义组件:
- 函数组件接收props作为参数,返回代表这个组件UI的React元素结构;
- 函数组件的写法比类组件的写法简洁,在使用无状态组件时,应该尽量将其定义为函数组件。
1.state、props
- React组件可以看作是一个函数,函数的输入是props和state,函数的输出是组件的UI;
- React组件正是由props和state两种类型的数据驱动渲染出组件UI;
- props是组件对外的接口,组件通过props接收外部传入的数据(包括方法);
- state是组件对内的接口,组件内部状态的变化通过state反映;
- props是只读的,不能再组件内部修改props;
- state是可变的,组件状态的变化通过修改state来实现。
2. 有状态组件、无状态组件
- 如果组件内部状态是不变的,即用不到state,这样的组件称为无状态组件;
- 如果组件内部状态是可变的,需要使用state来保存变化,这样的组件称为有状态组件;
- 无状态组件不用关心状态变化,只聚焦UI的展示,更容易复用,应该尽可能多地使用无状态组件;
- React应用组件设计的一般思路是:通过定义少数的有状态组件管理整个应用的状态变化,并且将状态通过props传递给其余的无状态组件,由无状态组件完成页面绝大部分UI的渲染工作。即,有状态组件主要关注处理状态变化的业务逻辑,无状态组件主要关注组件UI的渲染。
3.属性校验和默认属性
-
属性校验
- react 提供PorpType这个对象,用于校验组件的类型;
- 通过定义一个对象(对象的key是组件的属性名,value是对应属性的类型)实现组件属性类型的校验;
-
默认属性
- 通过组件的defaultProps来指定props的默认值。当组件属性未被赋值时,组件会使用defaultProps定义的默认属性。
4.组件样式
为组件添加样式的方法有两种:外部CSS样式表、内联样式
-
外部CSS样式表
- 引入CSS样式表的方式有两种:
- 在html页面中通过标签href引入;
这种方式常用于该样式文件作用于整个应用的所有组件
- 把样式表文件作为一个模块,通过import引入;
这种方式常用于该样式文件作用于某个组件(相当于组件的私有样式)
- 在html页面中通过标签href引入;
- 引入CSS样式表的方式有两种:
-
内联样式
- 内联样式实际是将CSS样式写到JS文件中,用JS对象表示CSS样式,然后通过DOM类型节点的style属性引用相应样式对象。
- 内联样式的样式属性名必须使用驼峰格式的命名。
5.组件和元素
-
React元素:
普通的javascript对象,这个对象通过DOM节点或React组件描述界面是什么样子的,JSX语法就是用来创建React元素的(JSX语法实际上是调用React.createElement方法);
-
React组件:
React组件是一个class或函数,接收一些属性作为输入,返回一个React元素。
6.组件的生命周期
-
挂载阶段
组件被创建,执行初始化,并被挂载到DOM中,完成组件的第一次渲染
- constructor
通常用于初始化组件的state以及绑定事件处理方法; - componentWillMount
在组件被挂载到DOM前调用,且只会被调用一次。在这个方法中调用this.setState不会引起组件的重新渲染。 - render
定义组件时唯一必要的方法,返回一个React的元素,用于描述组件的UI,注意:render并不负责组件的实际渲染工作,它只是返回一个UI的描述,真正的渲染出页面DOM的工作由React自身负责。render是一个纯函数,在这个方法中不能执行任何有福作用的操作,所以不能在render中调用this.setState,这会改变组件的状态。 - componentDidMount
在组件被挂载到DOM后调用,且只会被调用一次。这个方法通常会用于向服务器端请求数据,在这个方法中调用this.setState会引起组件的重新渲染。
- constructor
-
更细阶段
组件被挂载DOM后,组件的props或state可以引起组件更新。无论props是否改变,父组件render方法每一次调用,都会导致组件更新。State引起组件更新,是通过调用this.setState修改组件state来触发的。
组件更新阶段,依次被调用的生命周期方法:-
componentWillReceiveProps(nextProps)
- 这个方法只会在props引起的组件更新过程中,才会被调用。State引起的组件更新并不会触发该方法的执行。
- 参数nextProps是父组件传递给当前组件的新的props;
- 在componentWillReceiveProps中调用setState,只有在组件render及其之后的方法中,this.state指向的才是更新后的state。在render之前的方法shouldComponentUpdate、componentWillUpdate中,this.state依然指向的是更新前的state。
- 调用setState更新并不会触发componentWillReceiveProps的调用(否则可能会进入一个死循环)
-
shouldComponentUpdate(nextProps, nextState)
这个方法决定组件是否继续执行更新过程。当方法返回ture时,组件会继续更新过程;当方法返回false时,组件的更新过程停止,后续的componentWillUpdate、render、componentDidUpdate也不会再被调用。一般通过比较nextProps、nextState和组件当前的props、state决定这个方法的返回结果。这个方法可以用来减少组件的不必要的渲染,从而优化组件的性能。
-
componentWillUpdate
这个方法在组件render调用前执行,可以作为组件更新发生前执行某些工作的地方,一般很少用到。
shouldeComponentUpdate、componentWillUpdate中都不能调用setState,否则会引起循环调用问题,render将永远无法被调用,组件也无法正常渲染 -
render
-
componentDidUpdate(prevProps、prevState)
组件更新后被调用,可以作为操作更新后的DOM的地方。这个方法的两个参数prevProps、prevState代表组件更新前的props和state。
-
-
卸载阶段
组件从DOM中被卸载的过程,这个过程中只有一个生命周期方法:- componentWillUnmount
这个方法在组件被卸载前调用,可以执行一些清理工作,比如定时器、手动创建的DOM元素等。
- componentWillUnmount
** 只有类组件才具有生命周期方法,函数组件是没有生命周期方法的,因此永远不要在函数组件中使用生命周期方法 **
7.列表和keys
React使用key属性来标记列表中的每个元素,当列表数据发生变化时,React就可以通过key知道哪些元素发生了变化,从而只重新渲染发生变化的元素,提高渲染效率;
- 一般使用列表数据的ID作为key值;
- 如果列表包含的元素没有ID,也可以使用元素在列表中的位置索引作为key值;(但并不推荐使用索引作为key值,因为一旦列表中的数据发生重排,数据的索引也会发生变化,不利于React的渲染优化);
- 虽然列表元素的key不能重复,但这个唯一性仅限于当前列表中。
8.事件处理
React中的事件是合成事件,并不是原生的DOM事件。React根据W3C规范定义了一套兼容各个浏览器的事件对象。
- 在DOM事件中,可以通过处理函数返回false来阻止事件的默认行为,但在React事件中,必须显式地调用事件对象的preventDefault方法来阻止事件的默认行为。
- 在某些场景下必须使用DOM提供的原生事件,可以通过React事件对象的nativeEvent属性获取。
在React元素中绑定事件的注意事项:
- 在React中,事件的命名采用驼峰命名方式,而不是DOM元素中的小写字符命名方式;
- 处理事件的响应函数要以对象的形式赋值给事件属性,而不是DOM中的字符串形式;
React事件处理函数的写法主要有以下三种方式:
-
使用箭头函数
直接在React元素中采用箭头函数定义事件处理函数。
- 因为箭头函数中的this指向的是函数定义时的对象,所以可以保证this总是指向当前组件的实例对象;
- 直接在render方法中为元素事件定义处理函数,最大的问题是,每次render调用时,都会重新创建一个新的事件处理函数,带来额外的性能开销,组件所处层级越低,这种开销就越大,因为任何一个上层组件的变化都可能触发这个组件的render方法。
-
使用组件方法
直接将组件的方法赋值给元素的事件属性,同时在类的构造函数中,将这个方法的this绑定到当前对象。例如
- `this.handleClick = this.handlerClicke.bind(this)
- onClick=this.handleClick
这种方式的好处是每次render不会重新创建一个回调函数,没有额外的性能损失。但在构造函数中为事件处理函数绑定this,代码有些繁琐。
另一种方式,在为元素事件属性赋值时,同时绑定this,例如:
onClick=this.handleClick.bind(this)
使用bind会创建一个新的函数,因此这种写法依然存在每次render都会创建一个新函数的问题,但需要处理额外传参时,这种写法有用武之地,例如:onClicke = this.handleClick.bind(this, item) -
属性初始化语法(property initializer syntax)
使用ES7的property initializer 会自动为class中定义的方法绑定this。例如:handlerClicke = (event) => …
这种方式既不需要在构造函数中手动绑定this,也不需要担心组件重复渲染导致的函数重复创建问题。
9.表单
受控组件和非受控组件
- 受控组件
只需根据组件的属性和状态渲染即可,状态全部由React控制的组件,称为受控组件;
React采用受控组件技术,可以让一些非受控组件变为受控组件。- 非受控组件
组件自身维护的一些状态,与用户操作相关,状态不受React控制的组件,称为非受控组件;
** 受控组件和非受控组件的区别 **
- 受控组件保证了表单元素的状态统一由React管理,但需要为每个表单元素定义onChange事件的处理函数。
- 非受控组件需要React中提供的特殊属性ref,来引用React组件或DOM元素的实例,defaultValue指定默认值,后续值由组件自己控制。
- 非受控组件破坏了React对组件状态管理的一致性,往往容易出现不容易排查的问题,因此非特殊情况下,不建议使用。
三、React 16 新特性
1.render新的返回类型
React 16之前,render方法必须返回单个元素。现在,render方法支持两种新的返回类型:数组(由React元素组成)和字符串。
例如:
class ListComponent extends Component
render()
return [
<li key="A">First item</li>,
<li key="B">Second item</li>,
<li key="C">Third item</li>
];
class StringComponent extends Component
render()
return "Just a Strings";
2.错误处理
React 16之前,组件在运行期如果执行出错,就会阻塞整个应用的渲染;React 16引入了新的错误处理机制,默认情况下,当组件中抛出错误时,这个组件会从组件树中卸载,从而避免整个应用的崩溃。React 16还提供了一种更加友好的错误处理方式——错误边界(Error Boundaries)。错误边界是能够捕获子组件的错误并对其做优雅处理的组件。优雅的处理可以是输出日志、显示出错提示等。
定义了componetDidCatch(error, info)这个方法的组件将成为一个错误边界。
3.Portals
React 16的Portals特性让我们可以把组件渲染到当前组件树以外的DOM节点上,典型的应用场景是渲染应用的全局弹框,使用Portals后,任意组件都可以将弹框组件渲染到根节点上,以方便弹框的显示。
Protals的实现依赖ReactDOM的一个新的API:
ReactDOM.createPortal(child, container)
第一个参数child:是可以被渲染的React节点,例如React元素、由React元素组成的数组、字符串等,第二个参数container:是一个DOM元素,child将被挂载到这个DOM节点上。
4.自定义DOM属性
React 16之前会忽略不识别的HTML和SVG属性,现在React会把不识别的属性传递给DOM元素。
以上是关于React笔记1的主要内容,如果未能解决你的问题,请参考以下文章