前言

最近在看 React 的新语法—— React Hooks,只能一句话概括:React 语法真的是越来越强大,越写代码越少。

强烈推荐还没看 React Hooks 的同学去学习下,这会让你写react 项目变得非常爽!

以前 React 组件可以看成是: 无状态组件(function定义)和有状态组件(class 定义),React Hooks 出现之后,我们基本所有的组件都可以用function定义,包括有组态组件,基本废除了 写 class 语法的 复杂性,让我们写代码真正变成了函数式编程。

状态 Hooks(useState)

这里说明一点,react中所有的Hooks都是一种函数,函数都是用来实现特定功能的。

useState 提供了创建组件state的功能,用法:

const [count, setCount] = useState(0)

useState() 接受唯一一个状态初始值参数,返回包含状态和改变状态对应的函数的数组,这里采用 数组解构方法获得 状态变量 count ,改变状态方法 setCount。

强调一点:

useState() 传入的初始值不一定非要是个对象,可以为普通数据类型,比如:Number,String等,初始值用作组件初次渲染。

setCount() 接受一个全新的state状态,react会直接全部替换掉原来的state状态,这点和 setState() 有所不同。

Example:

import React, { useState } from 'react';
function Example(){
const [ count , setCount ] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={()=>{setCount(count+1)}}>click me</button>
</div>
)
}
export default Example;

当把 Example 组件渲染到页面上时,可以通过点击按钮实时改变 count 状态,react 也会根据状态改变重新渲染页面。

执行副作用操作Hooks(useEffect)

之前在写 react 组件时,往往我们在组件的生命周期函数里面做一些额外的操作,比如发送ajax请求获取数据,清除定时器和异步执行任务等。

我们发现这样操作重复的代码很多,而且如果对于 react 生命周期钩子不熟悉的话,很容易出错,于是乎,useEffect() Hooks 出现了。

useEffect() hooks 可以允许我们在 react 函数式组件中执行一些额外的副作用操作。

在 React 组件中有两种常见副作用操作:

  • 需要清除的,比如开启的定时器,订阅外部数据源等,这些操作如果在组件消亡后不及时清除会导致内存泄漏。

  • 不需要清除的,比如发起网络请求,手动变更 DOM,记录日志等。

在 react 官网中有一段话很重要:

如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。

Example:


import React, { useState , useEffect } from 'react';
function Example(){
const [ count , setCount ] = useState(0);
useEffect(()=>{
console.log(`You clicked ${count} times`)
})
return (
<div>
<p>You clicked {count} times</p>
<button onClick={()=>{setCount(count+1)}}>click me</button>
</div>
)
}
export default Example;

我们在刚才的例子上新增了一个功能,每次我们 count 状态改变的时候都会在控制台打印出我们点击的次数。可以看到使用 useEffect() Hooks 轻松实现。

强调一点:

  • react首次渲染和之后的每次渲染都会调用一遍useEffect函数,而之前我们要用两个生命周期函数分别表示首次渲染(componentDidMonut)和更新导致的重新渲染(componentDidUpdate)。

  • useEffect中定义的函数的执行不会阻碍浏览器更新视图,也就是说这些函数是异步执行的,而componentDidMonut和componentDidUpdate中的代码都是同步执行的。

  • 可以为 useEffect() 传入第二个参数,它是一个数组,数组里面表示这个副作用的操作依赖的状态变量,换句话说:如果这个副作用的操作依赖的状态变量没有改变,则不会执行副作用操作。

组件之间传值Hooks(useContext)

之前在用类声明组件时,父子组件的传值是通过组件属性和props进行的,那现在使用方法(Function)来声明组件,已经没有了constructor构造函数也就没有了props的接收,那父子组件的传值就成了一个问题。React Hooks 为我们准备了useContext。

useContext它可以帮助我们跨越组件层级直接传递变量,实现共享。

Example:

一:利用 createContext 创建上下文


import React, { useState , createContext } from 'react'; // 创建一个 CountContext
const CountContext = createContext() function Example(){
const [ count , setCount ] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={()=>{setCount(count+1)}}>click me</button>
{/* 将 context 传递给 子组件,context 值由value props决定*/}
<CountContext.Provider value={count}>
<Counter/>
</CountContext.Provider>
</div>
)
}
export default Example;

二:使用useContext 获取上下文

对于要接收context的后代组件,只需引入 useContext() Hooks 即可。


function Counter(){
const count = useContext(CountContext) //一句话就可以得到count
return (<h2>{count}</h2>)
}

强调一点:

useContext 的参数必须是 context 对象本身:

  • 正确: useContext(MyContext)
  • 错误: useContext(MyContext.Consumer)
  • 错误: useContext(MyContext.Provider)

当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 <MyContext.Provider> 的 context value 值。

处理更为复杂state结构的Hooks(useReducer)

前面我们使用的 useState Hooks可以为组件提供 state和操作改变state状态的方法,但往往有时候我们的state 结构更为复杂,例如 state 包含多个子值,或者下一个 state 依赖于之前的 state 等,这时候 useReducer 比 useState 更合适。

useReducer 的用法:


const [state, dispatch] = useReducer(reducer, initialArg, init);

useReducer 接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。

我们可以使用 useReducer 来重新写我们开篇计数器的demo:

Example:


const initialState = {count: 0}; function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
return state
}
}
// 定义 Counter 组件
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
Count: {state.count}
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</div>
);
}

对于熟悉 redux 的伙伴,这种写法很容易就能理解,每次通过点击按钮分发一个action来更新state状态数据。

强调一点:

React 不使用 state = initialState 这一由 Redux 推广开来的参数约定。有时候初始值依赖于 props,因此需要在调用 Hook 时指定。如果你特别喜欢上述的参数约定,可以通过调用 useReducer(reducer, undefined, reducer) 来模拟 Redux 的行为,但我们不鼓励你这么做。

这里是 react 官网提供的一句话,也就是说我们为 state 提供初始值的时候不能够像 redux 中利用 ES6 默认参数来指定,必须得通过 useReducer来指定。这个切记,因为我也踩过坑!

对于 useReducer 和 useState的区别主要是以下两点:

  • 当 state 状态值结构比较复杂时,使用 useReducer 更有优势。
  • 使用 useState 获取的 setState 方法更新数据时是异步的;而使用 useReducer 获取的 dispatch 方法更新数据是同步的。

性能优化Hooks(useMemo)

我们知道 使用class 形式的组件有着生命周期 shouldCompnentUpdate函数用来优化组件的性能,防止每次渲染造成昂贵的开销。

使用function的形式来声明组件,失去了shouldCompnentUpdate(在组件更新之前)这个生命周期,也就是说我们没有办法通过组件更新前条件来决定组件是否更新。而且在函数组件中,也不再区分mount和update两个状态,这意味着函数组件的每一次调用都会执行内部的所有逻辑,就带来了非常大的性能损耗。

useMemo主要用来解决使用React hooks产生的无用渲染的性能问题。

举个例子:

在 A 组件中有两个子组件 B 和 C,当 A 组件中传给 B 的 props 发生变化时,A 组件状态会改变,重新渲染。此时 B 和 C 也都会重新渲染。其实这种情况是比较浪费资源的,现在我们就可以使用 useMemo 进行优化,B 组件用到的 props 变化时,只有 B 发生改变,而 C 却不会重新渲染。

Example:


// A 组件 import React from 'react'; export default ({ text }) => {
console.log('component A:', 'render');
return <div> A 组件:{ text }</div>
} // B 组件 import React from 'react'; export default ({ text }) => {
console.log('component B:', 'render');
return <div> B 组件:{ text }</div>
} // App 组件 import React, { useState, useMemo } from 'react';
import A from './ExampleA';
import B from './ExampleB'; export default () => {
const [a, setA] = useState('A');
const [b, setB] = useState('B'); const exampleA = useMemo(() => <A text={a} />, [a]);
const exampleB = useMemo(() => <B text={b} />, [b]); return (
<div>
{ exampleA }
{ exampleB }
<br />
<button onClick={ () => setA('A改变了') }>修改传给 A 的属性</button>
&nbsp;&nbsp;&nbsp;&nbsp;
<button onClick={ () => setB('B改变了') }>修改传给 B 的属性</button>
</div>
)
}

我们点击不同的按钮,控制台都只会打印一条输出,改变 a 或者 b,A 和 B 组件都只有一个会重新渲染。

其实 React 还有很多常用的 Hooks,比如用来获取DOM元素 和保存变量的useRef,优化函数式组件性能的useCallback等,对于这些的Hooks大家可以去react 官网了解下,相信大家应该也能搞清楚,这里就不做进一步探讨。

React Hooks Api

结语

本篇文章出自于我们 web-study 仓库,如果喜欢的话,欢迎给个 star!

地址: web-study

React Hooks 你不来了解下?的更多相关文章

  1. 初探React Hooks & SSR改造

    Hooks React v16.8 发布了 Hooks,其主要是解决跨组件.组件复用的状态管理问题. 在 class 中组件的状态封装在对象中,然后通过单向数据流来组织组件间的状态交互.这种模式下,跨 ...

  2. React hooks实践

    前言 最近要对旧的项目进行重构,统一使用全新的react技术栈.同时,我们也决定尝试使用React hooks来进行开发,但是,由于React hooks崇尚的是使用(也只能使用)function c ...

  3. React Hooks新特性学习随笔

    React Hooks 是 React 16.8 的新增特性.它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性. 前言 本篇主要以讲几个常用的api为主. 1.u ...

  4. 关于React Hooks,你不得不知的事

    React Hooks是React 16.8发布以来最吸引人的特性之一.在开始介绍React Hooks之前,让咱们先来理解一下什么是hooks.wikipedia是这样给hook下定义的: In c ...

  5. react新特性 react hooks

    本文介绍的是react新特性react hooks,本文面向的是有一定react开发经验的小伙伴,如果你对react还不是很熟悉的话我建议你先学习react并多多联系. 首先我们都知道react有3种 ...

  6. 30分钟精通React今年最劲爆的新特性——React Hooks

    你还在为该使用无状态组件(Function)还是有状态组件(Class)而烦恼吗? --拥有了hooks,你再也不需要写Class了,你的所有组件都将是Function. 你还在为搞不清使用哪个生命周 ...

  7. React Hooks用法大全

    前言 在 React 的世界中,有容器组件和 UI 组件之分,在 React Hooks 出现之前,UI 组件我们可以使用函数,无状态组件来展示 UI,而对于容器组件,函数组件就显得无能为力,我们依赖 ...

  8. React Hooks 深入系列

    本文基于近段时间对 hooks 碎片化的理解作一次简单梳理, 个人博客.同时欢迎关注基于 hooks 构建的 UI 组件库 -- snake-design. 在 class 已经融入 React 生态 ...

  9. React Hooks --- useState 和 useEffect

    首先要说的一点是React Hooks 都是函数,使用React Hooks,就是调用函数,只不过不同的Hooks(函数)有不同的功能而已.其次,React Hooks只能在函数组件中使用,函数组件也 ...

随机推荐

  1. DT-06 For Homekit

    一. 配置DT-06上网 连接此热点,会自动弹出wifi配置页面. 输入选中的路由密码,点 Join加入,如果路由没有出现在列表中,点 Other手工输入(仅支持2.4g路由配置) 二.配置dt-06 ...

  2. Java学习|多线程学习笔记

    什么是线程?     可以理解为进程中独立运行的字任务.   使用多线程:     1.继承Thread类:从源码可以看到,Thread累实现了Runnable接口.         如果多次调用st ...

  3. redpwnctf-web-blueprint-javascript 原型链污染学习总结

    前几天看了redpwn的一道web题,node.js的web,涉及知识点是javascript 原型链污染,以前没咋接触过js,并且这个洞貌似也比较新,因此记录一下学习过程 1.本机node.js环境 ...

  4. 贪心算法-过河问题 pojo1700

    过桥问题: 黑夜,只有一只手电筒 A过桥需要1s B过桥需要3s C过桥需要5s D过桥需要8s E过桥需要12s 求最小过桥时间 贪心算法: 从最大的开始过去,最小的两个做为辅助. 假如左岸人数为2 ...

  5. 用小程序·云开发两天搭建mini论坛丨实战

    笔者最近涉猎了小程序相关的知识,于是利用周末时间开发了一款类似于同事的小程序,深度体验了小程序云开发模式提供的云函数.数据库.存储三大能力.关于云开发,可参考文档:小程序·云开发. 个人感觉云开发带来 ...

  6. GSS系列

    GSS1 直接维护静态区间和即可 #include<bits/stdc++.h> using namespace std; ; int n,a[N]; ]; inline void pus ...

  7. NNs(Neural Networks,神经网络)和Polynomial Regression(多项式回归)等价性之思考,以及深度模型可解释性原理研究与案例

    1. Main Point 0x1:行文框架 第二章:我们会分别介绍NNs神经网络和PR多项式回归各自的定义和应用场景. 第三章:讨论NNs和PR在数学公式上的等价性,NNs和PR是两个等价的理论方法 ...

  8. PythonI/O进阶学习笔记_1.抽象、面向对象、class/object/type

    前言: 是自己在学习python进阶IO学习视频的时候的理解和笔记,因为很多都是本菜鸟学习时候的自己的理解,有可能理解有误. Content: - 抽象的概念和面向对象的概念?想要大概了解python ...

  9. python 21 面向对象

    目录 1. 面向对象初步认识 2. 面向对象的结构 3. 从类名的角度研究类 3.1 类名操作类中的属性 3.2 类名调用类中的方法 4. 从对象的角度研究类 4.1 类名() 4.2 对象操作对象空 ...

  10. Python多进程的Join和daemon(守护)的用法

    join和daemon 下面仅以多进程为例: 知识点一: 当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行流的最小单元,当设置多线程时,主线程会创建多个子线程,在python中,默认情况下 ...