记录React相关知识点

前言:React 是一个用于构建用户界面的 JavaScript 库 。

Props

组件无论是使用函数声明还是通过 class 声明,都决不能修改自身的 props。所有 React 组件都必须像纯函数不更改自己的入参则是纯函数)一样保护它们的 props 不被更改。

State

  • 不要直接修改State,应该使用setState()
  • State 的更新可能是异步的:setState() 可以接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数
  • State 的更新会被合并

生命周期

在这里插入图片描述

挂载卸载过程
  • constructor()
    完成React数据的初始化,接受两个参数:props、context。当想在函数内部使用这两个参数时,需使用super()传入这两个参数。只要使用了constructor(),就必须使用super(),否则会导致this指向错误。
  • componentWillMount()
    组件已经经历了constructor()初始化数据后,但是还未渲染DOM时。一般用的比较少,它更多的是在服务端渲染时使用。
  • componentDidMount()
    组件第一次渲染完成,此时dom节点已经生成。在此处做数据处理
  • componentWillUnmount ()
    在此处完成组件的卸载和数据的销毁。
更新过程
  • componentWillReceiveProps (nextProps)
    在接受父组件改变后的props需要重新渲染组件时
  • shouldComponentUpdate(nextProps,nextState)
    主要用于性能优化(部分更新) 唯一用于控制组件重新渲染的生命周期,由于在react中,setState以后,state发生变化,组件会进入重新渲染的流程,在这里return false可以阻止组件的更新
  • componentWillUpdate (nextProps,nextState)
    shouldComponentUpdate返回true以后,组件进入重新渲染的流程时
  • componentDidUpdate(prevProps,prevState)
    组件更新完毕后,react只会在第一次初始化成功会进入componentDidmount,之后每次重新渲染后都会进入这个生命周期,这里可以拿到prevProps和prevState,即更新前的props和state。
  • render()
    render函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染。

React如何阻止无效重渲染

如果你的组件只有当 props中某个值或者 state中某个值改变才需要更新时,你可以使用 shouldComponentUpdate 来进行检查,返回true则渲染false则不渲染。

class CounterButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: 1};
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (this.props.color !== nextProps.color) {
      return true;
    }
    if (this.state.count !== nextState.count) {
      return true;
    }
    return false;
  }

  render() {
    return (
      <button
        color={this.props.color}
        onClick={() => this.setState(state => ({count: state.count + 1}))}>
        Count: {this.state.count}
      </button>
    );
  }
}

大部分情况下,可以继承React.PureComponent 实现。

class CounterButton extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {count: 1};
  }

  render() {
    return (
      <button
        color={this.props.color}
        onClick={() => this.setState(state => ({count: state.count + 1}))}>
        Count: {this.state.count}
      </button>
    );
  }

当然这种方式也有不足的地方,它只是进行浅比较,当 props 或者 state 某种程度是可变的话,浅比较会有遗漏,那你就不能使用它了。PureComponent 仅仅会对新老 this.props 的值进行简单的对比。避免该问题最简单的方式是避免更改你正用于 props 或 state 的值。

//原代码
handleClick() {
    // 这部分代码很糟,而且还有 bug
    const words = this.state.words;
    words.push('marklar');
    this.setState({words: words});
}
//更正后
handleClick() {
  this.setState(state => ({
    words: state.words.concat(['marklar'])
  }));
}
//ES6数组支持扩展运算符
handleClick() {
  this.setState(state => ({
    words: [...state.words, 'marklar'],
  }));
};
//Object.assign
function updateColorMap(colormap) {
  return Object.assign({}, colormap, {right: 'blue'});
}

受控组件与非受控组件

event.preventDefault():阻止事件的默认行为,不会影响事件的传递

受控组件

在 HTML 中,表单元素(如<input><textarea><select> 之类的表单元素通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state属性中,并且只能通过使用 setState()来更新。
两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleChange(event) {
    this.setState({value: event.target.value});
  }
  handleSubmit(event) {
    console.log('文本框输入的值是:' + this.state.value);
    event.preventDefault();
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          名字:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="提交" />
      </form>
    );
  }
}
非受控组件

使用非受控组件,表单数据交由DOM节点来处理。

  • 创建Refs:可以通过==React.createRef()==创建Refs并通过ref属性联系到React组件。Refs通常当组件被创建时被分配给实例变量,这样它们就能在组件中被引用。
  • 访问Refs: 当一个ref通过render放入一个元素中,一个对节点的引用可以通过ref的current属性得到;const node = this.myRef.current;
  • PS:在 React 中,<input type="file" /> 始终是一个非受控组件,因为它的值只能由用户设置,而不能通过代码控制。
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.input= React.createRef();
    this.handleSubmit = this.handleSubmit.bind(this);
  }
   handleSubmit(event) {
    console.log('文本框输入的值是:' + this.input.current.value);
    event.preventDefault();
  }
  render() {
    return (
		<form onSubmit={this.handleSubmit}>
        	<label>
          		Name:
          		<input type="text" ref={this.input} />
        	</label>
        	<input type="submit" value="Submit" />
		</form>
	);
  }
}

如果只想得到表单的value,代码可以这样写,区别在于ref的定义

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
   handleSubmit(event) {
    console.log('文本框输入的值是: ' + this.input.value);
    event.preventDefault();
  }
  render() {
    return (
		<form onSubmit={this.handleSubmit}>
        	<label>
          		Name:
          		<input type="text" ref={ref => this.input = ref} />
        	</label>
        	<input type="submit" value="Submit" />
		</form>
	);
  }
}
二者分别适用于什么场景
场景受控组件非受控组件
一次性取值(例如在提交时)
提交时验证
即时现场验证
有条件地禁用提交按钮
强制输入格式
一个数据的多个输入
动态输入

Hook

  • Hook 是React 16.8的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
  • Hook 在 class 内部是起作用的。
  • 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
  • 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。(自定义的 Hook 中可以调用Hook)
State Hook(useState)
  • 调用 useState 方法的时: 它定义一个 “state 变量”。我们的变量叫 count, 但是我们可以叫他任何名字,比如 banana。这是一种在函数调用时保存变量的方式 —— useState 是一种新方法,它与 class 里面的 this.state 提供的功能完全相同。一般来说,在函数退出后变量就会”消失”,而 state 中的变量会被 React 保留。
  • useState 需要哪些参数:useState() 方法里面唯一的参数就是初始 state。不同于 class 的是,我们可以按照需要使用数字或字符串对其进行赋值,而不一定是对象。
  • useState 方法的返回值是什么:当前 state 以及更新 state 的函数
import React, { useState } from 'react'; //引入useState 
function Example() {
 	// 声明一个叫 "count" 的 state 变量
	const [count, setCount] = useState(0);
	return (
		<div>
        	<p>You clicked {count} times</p> //读取state,直接使用count
        	<button onClick={() => setCount(count + 1)}>Click me</button> //更新state,直接调用setCount
		</div>
	);
}

以上使用Hook的函数组件等同于如下的class组件

import React from 'react';
class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }
  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}
Effect Hook(useEffect)
  • Effect Hook 可以让你在函数组件中执行副作用操作,可以在这里告诉 React 组件需要在渲染后执行某些操作
  • 可以把 useEffect Hook 看做 componentDidMountcomponentDidUpdatecomponentWillUnmount 这三个函数的组合
  • 默认情况下,useEffect 在第一次渲染之后和每次更新之后都会执行。React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。
  • 允许按照代码的用途分离useEffect。React 将按照 effect 声明的顺序依次调用组件中的每一个 effect。
需要清除的 effect
  • class组件的清除工作在生命周期函数componentWillUnmount 执行
  • 而在这里,每个 effect 都可以返回一个清除函数,这是 effect 可选的清除机制
  • effect 的清除阶段在每次重新渲染时都会执行,而不是只在卸载组件的时候执行一次。这个设计可以帮助我们创建 bug 更少的组件。(在 class 组件中,我们需要添加 componentDidUpdate来解决)
如何跳过 Effect 进行性能优化
  • 在class组件中,通过在 componentDidUpdate 中添加对 prevProps 或 prevState 的比较逻辑解决
  • 而在这里,只要传递数组作为 useEffect 的第二个可选参数即可
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新

如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数
如果你传入了一个空数组([]),effect 内部的 props 和 state 就会一直拥有其初始值。
React 会等待浏览器完成画面渲染之后才会延迟调用 useEffect

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值