React hooks实践
前言
最近要对旧的项目进行重构,统一使用全新的react技术栈。同时,我们也决定尝试使用React hooks来进行开发,但是,由于React hooks崇尚的是使用(也只能使用)function component的形式来进行开发,而不是class component,因此,整个开发方式也会与之前产生比较大的差异。所以,我这里就积累了下实际项目中遇到的问题以及思考,看下能不能帮助大家少走弯路。
正文
接下来就直接进入正文。我会将项目中遇到的问题一一列举出来,并且给出解决方案。
执行初始化操作的时机
当我转到React hooks的时候,首先就遇到了这个问题:
一般来说,业务组件经常会遇到要通过发起ajax请求来获取业务数据并且执行初始化操作的场景。在使用class component编程的时候,我们就可以在class component提供的生命周期钩子函数(比如componentDidMount, constructor等)执行这个操作。可是如果转到React hooks之后,function component里是没有这个生命周期钩子函数的,那这个初始化操作怎么办呢?总不能每次遇到这种场景都使用class component来做吧?
解决方案:使用useEffect(想知道useEffect是什么的话,可以点击这里)
useEffect,顾名思义,就是执行有副作用的操作,你可以把它当成componentDidMount
, componentDidUpdate
, and componentWillUnmount
的集合。它的函数声明如下
useEffect(effect: React.EffectCallback, inputs?: ReadonlyArray<any> | undefined)
那么,我们在实际使用中,我们就可以使用这个来执行初始化操作。举个例子
import React, { useEffect } from 'react'
export function BusinessComponent() {
const initData = async () => {
// 发起请求并执行初始化操作
}
// 执行初始化操作,需要注意的是,如果你只是想在渲染的时候初始化一次数据,那么第二个参数必须传空数组。
useEffect(() => {
initData();
}, []);
return (<div></div>);
}
需要注意的是,这里的useEffect的第二个参数必须传空数组,这样它就等价于只在componentDidMount的时候执行。如果不传第二个参数的话,它就等价于componentDidMount和componentDidUpdate
做一些清理操作
由于我们在实际开发过程中,经常会遇到需要做一些副作用的场景,比如轮询操作(定时器、轮询请求等)、使用浏览器原生的事件监听机制而不用react的事件机制(这种情况下,组件销毁的时候,需要用户主动去取消事件监听)等。使用class Component编程的时候,我们一般都在componentWillUnmount或者componentDidUnmount的时候去做清理操作,可是使用react hooks的时候,我们如何做处理呢?
解决方案:使用useEffect第一个参数的返回值
如果useEffect的第一个参数返回了函数的时候,react会在每一次执行新的effects之前,执行这个函数来做一些清理操作。因此,我们就可以使用它来执行一些清理操作。
例子:比如我们要做一个二维码组件,我们需要根据传入的userId不断轮询地向后台发请求查询扫描二维码的状态,这种情况下,我们就需要在组件unmount的时候清理掉轮询操作。代码如下:
import React, { useEffect } from 'react'
export function QRCode(url, userId) {
// 根据userId查询扫描状态
const pollingQueryingStatus = async () => {
}
// 取消轮询
const stopPollingQueryStatus = async() => {
}
useEffect(() => {
pollingQueryingStatus();
return stopPollingQueryStatus;
}, []);
// 根据url生成二维码
return (<div></div>)
}
这样的话,就等价于在componentWillUnmount的时候去执行清理操作。
但是,有时候我们可能需要执行多次清理操作。还是举上面的例子,我们需要在用户传入新的userId的时候,去执行新的查询的操作,同时我们还需要清除掉旧的轮询操作。想一下怎么做比较好。
其实对这种情况,官方也已经给出了解决方案了,useEffect的第二个参数是触发effects的关键,如果用户传入了第二个参数,那么只有在第二个参数的值发生变化(以及首次渲染)的时候,才会触发effects。因此,我们只需要将上面的代码改一下:
import React, { useEffect } from 'react'
export function QRCode(url, userId) {
// 根据userId查询扫描状态
const pollingQueryingStatus = async () => {
}
const stopPollingQueryStatus = async() => {
}
// 我们只是将useEffect的第二个参数加了个userId
useEffect(() => {
pollingQueryingStatus();
return stopPollingQueryStatus;
}, [userId]);
// 根据url生成二维码
return (<div></div>)
}
我们只是在useEffect的第二个参数数组里,加入了一个userId。这样的话,userId的每一次变化都会先触发stopPollingQueryStatus,之后再执行effects,这样就可以达到我们的目的。
useState与setState的差异
react hooks使用useState来代替class Component里的state。可是,在具体开发过程中,我也发现了一些不同点。useState介绍可以点击这里
在setState的时候,我们可以只修改state中的局部变量,而不需要将整个修改后的state传进去,举个例子
import React, { PureComponent } from 'react';
export class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
name: 'cjg',
age: 18,
}
}
handleClick = () => {
const { count } = this.state;
// 我们只需要传入修改的局部变量
this.setState({
count: count + 1,
});
}
render() {
return (
<button onClick={this.handleClick}></button>
)
}
}
而使用useState后,我们修改state必须将整个修改后的state传入去,因为它会直接覆盖之前的state,而不是合并之前state对象。
import React, { useState } from 'react';
export function Count() {
const [data, setData] = useState({
count: 0,
name: 'cjg',
age: 18,
});
const handleClick = () => {
const { count } = data;
// 这里必须将完整的state对象传进去
setData({
...data,
count: count + 1,
})
};
return (<button onClick={handleClick}></button>)
}
减少不必要的渲染
在使用class Component进行开发的时候,我们可以使用shouldComponentUpdate
来减少不必要的渲染,那么在使用react hooks后,我们如何实现这样的功能呢?
解决方案:React.memo和useMemo
对于这种情况,react当然也给出了官方的解决方案,就是使用React.memo和useMemo。
React.memo
React.momo其实并不是一个hook,它其实等价于PureComponent,但是它只会对比props。使用方式如下(用上面的例子):
import React, { useState } from 'react';
export const Count = React.memo((props) => {
const [data, setData] = useState({
count: 0,
name: 'cjg',
age: 18,
});
const handleClick = () => {
const { count } = data;
setData({
...data,
count: count + 1,
})
};
return (<button onClick={handleClick}>count:{data.count}</button>)
});
useMemo
useMemo它的用法其实跟useEffects有点像,我们直接看官方给的例子
function Parent({ a, b }) {
// Only re-rendered if `a` changes:
const child1 = useMemo(() => <Child1 a={a} />, [a]);
// Only re-rendered if `b` changes:
const child2 = useMemo(() => <Child2 b={b} />, [b]);
return (
<>
{child1}
{child2}
</>
)
}
从例子可以看出来,它的第二个参数和useEffect的第二个参数是一样的,只有在第二个参数数组的值发生变化时,才会触发子组件的更新。
总结
一开始在从class component转变到react hooks的时候,确实很不适应。可是当我习惯了这种写法后,我的心情如下:
当然,现在react hooks还是在alpha阶段,如果大家觉得不放心的话,可以再等等。反正我就先下手玩玩了哈哈哈。
本文地址在->本人博客地址, 欢迎给个 start 或 follow
React hooks实践的更多相关文章
- 理解 React Hooks
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由志航发表于云+社区专栏 TL;DR 一句话总结 React Hooks 就是在 react 函数组件中,也可以使用类组件(classe ...
- React Hooks用法大全
前言 在 React 的世界中,有容器组件和 UI 组件之分,在 React Hooks 出现之前,UI 组件我们可以使用函数,无状态组件来展示 UI,而对于容器组件,函数组件就显得无能为力,我们依赖 ...
- React Hooks实现异步请求实例—useReducer、useContext和useEffect代替Redux方案
本文是学习了2018年新鲜出炉的React Hooks提案之后,针对异步请求数据写的一个案例.注意,本文假设了:1.你已经初步了解hooks的含义了,如果不了解还请移步官方文档.(其实有过翻译的想法, ...
- React Hooks 实现react-redux
Redux 是目前 React 系统中最常用的数据管理工具,它落实并发扬了 Flux 的数据单向流动模式,被实践证明为一种成熟可用的模式. 尽管承受着一些非议,Redux 在 React 数据管理界的 ...
- 蒲公英 · JELLY技术周刊 Vol.21 -- 技术周刊 · React Hooks vs Vue 3 + Composition API
蒲公英 · JELLY技术周刊 Vol.21 选 React 还是 Vue,每个人心中都会有自己的答案,有很多理由去 pick 心水的框架,但是当我们扪心自问,我们真的可以公正的来评价这两者之间的差异 ...
- 通过 React Hooks 声明式地使用 setInterval
本文由云+社区发表 作者:Dan Abramov 接触 React Hooks 一定时间的你,也许会碰到一个神奇的问题: setInterval 用起来没你想的简单. Ryan Florence 在他 ...
- 初探React Hooks & SSR改造
Hooks React v16.8 发布了 Hooks,其主要是解决跨组件.组件复用的状态管理问题. 在 class 中组件的状态封装在对象中,然后通过单向数据流来组织组件间的状态交互.这种模式下,跨 ...
- [转] React 最佳实践——那些 React 没告诉你但很重要的事
前言:对很多 react 新手来说,网上能找到的资源大都是些简单的 tutorial ,它们能教会你如何使用 react ,但并不会告诉你怎么在实际项目中优雅的组织和编写 react 代码.用谷歌搜中 ...
- React Hooks新特性学习随笔
React Hooks 是 React 16.8 的新增特性.它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性. 前言 本篇主要以讲几个常用的api为主. 1.u ...
随机推荐
- 关于浏览器cookie的小知识
浏览器对于总的cookie数量是没有限制的,但是对于每个域名的cookie数量是有限制的. 一,不同的浏览器,对于一个域名的cookie数量限制上限是不同的: 1,IE6以下版本,最多20个.IE7以 ...
- Unity3D InputManager详解
首先说一下 Input 类,这个类很常用,API 大家基本都知道,这里记录几个使用频率没那么高的 API Input.acceleration:重力加速度传感器的值,加速度的方向,适用于移动平台. I ...
- 洛谷P1443 马的遍历
https://www.luogu.org/problemnew/show/P1443 很经典的搜索题了,蒟蒻用广搜打的 不说了,上代码! #include<bits/stdc++.h> ...
- docker install
1.安装必要工具集 sudo yum install -y yum-utils 2.安装Docker官方源 sudo yum-config-manager \ --add-repo \ https:/ ...
- quartus 一种管脚分配方法
第一步: 在QII软件中,使用“Assignments -> Remove Assignments”标签,移除管脚分配内容,以确保此次操作,分配的管脚没有因为覆盖而出现错误的情况. 编写xxx. ...
- 【java源码】解读HashTable类背后的实现细节
HashTable这个类实现了哈希表从key映射到value的数据结构形式.任何非null的对象都可以作为key或者value. 要在hashtable中存储和检索对象,作为key的对象必须实现has ...
- python 上传文件
上周产品给我提了个需求,大体是做一个后台系统,管理游戏比赛落地页的数据更新,难点在于需要给CDN上传文件.现在把经验记录下来,下次有类似的需求能提高开发效率. 我使用的是网宿CDN,没有用网宿的SDK ...
- 12Js_原型对象
对象描述: 1. 每个对象中都有一个_proto_属性. JS世界中没有类(模具)的概念,对象是从另一个对象(原型)衍生出来的,所以每个对象中会有一个_proto_属性指向它的原型对象.(参考左上角的 ...
- 【云盘资料】Sql注入从菜鸟到高手系列教程
[云盘资料]Sql注入从菜鸟到高手系列教程 ps:Sql注入从菜鸟到高手系列教程 链接:阅读原文获取资料:http://bbs.ichunqiu.com/thread-6851-1-1.html 反馈 ...
- Windows下编译安装 FFmpeg
在Linux/Mac下编译 ffmpeg是非常方便的.但要在 Windows下编译 ffmpeg还真要花点时间.以下就是在 Windowns下编译ffmpeg的步骤: 一.安装Cygwin 在wind ...