In the class version of this component, we had a method called safeSetState which would check whether the component was still mounted before trying to call setState. This is because our graphql client library is unable to cancel in-flight requests. Let's make that same kind of thing work by tracking the mounted state of our component using the useRef and useEffect hooks.

We want a "lock", which should run once when component inited, after component unmounted, it should be reseted.

We can use 'useRef' to build a container to hold our lock:

  const mountedRef = useRef(false);

Then we can use useEffect:

  useEffect(() => {
mountedRef.current = true
return () => (mountedRef.current = false)
}, [])

The reason to use '[]' as second arguement, is because we don't want useEffect be triggered second times, we only want to run once, therefore, we use empty array, it won't trigger scecond time.

Then we can create a safe setSetate function:

  const [state, setState] = useReducer(
(state, newState) => ({...state, ...newState}),
{
loaded: false,
fetching: false,
data: null,
error: null,
},
) const setSafeState = (...args) => mountedRef.current && setState(...args);

----

Full code:

import {useContext, useReducer, useEffect, useRef} from 'react'
import PropTypes from 'prop-types'
import isEqual from 'lodash/isEqual'
import * as GitHub from '../../../github-client' function useSetState(initialState) {
return useReducer(
(state, newState) => ({...state, ...newState}),
initialState,
)
} function useSafeSetState(initialState) {
const [state, setState] = useSetState(initialState) const mountedRef = useRef(false)
useEffect(() => {
mountedRef.current = true
return () => (mountedRef.current = false)
}, [])
const safeSetState = (...args) => mountedRef.current && setState(...args) return [state, safeSetState]
} function Query({query, variables, normalize = data => data, children}) {
const client = useContext(GitHub.Context)
const [state, setState] = useSafeSetState({
loaded: false,
fetching: false,
data: null,
error: null,
}) useEffect(() => {
if (isEqual(previousInputs.current, [query, variables])) {
return
}
setState({fetching: true})
client
.request(query, variables)
.then(res =>
setState({
data: normalize(res),
error: null,
loaded: true,
fetching: false,
}),
)
.catch(error =>
setState({
error,
data: null,
loaded: false,
fetching: false,
}),
)
}) const previousInputs = useRef()
useEffect(() => {
previousInputs.current = [query, variables]
}) return children(state)
} Query.propTypes = {
query: PropTypes.string.isRequired,
variables: PropTypes.object,
children: PropTypes.func.isRequired,
normalize: PropTypes.func,
} export default Query

[React] Safely setState on a Mounted React Component through the useEffect Hook的更多相关文章

  1. React的setState分析

    前端框架层出不穷,不过万变不离其宗,就是从MVC过渡到MVVM.从数据映射到DOM,angular中用的是watcher对象,vue是观察者模式,react就是state了. React通过管理状态实 ...

  2. React的setState执行机制

    1. setState基本特点 1. setState是同步执行的 setState是同步执行的,但是state并不一定会同步更新 2. setState在React生命周期和合成事件中批量覆盖执行 ...

  3. React中setState同步更新策略

    setState 同步更新 我们在上文中提及,为了提高性能React将setState设置为批次更新,即是异步操作函数,并不能以顺序控制流的方式设置某些事件,我们也不能依赖于this.state来计算 ...

  4. 初学React,setState后获取到的thisstate没变,还是初始state?

    问题:(javascript)初学React,setState后获取到的thisstate没变,还是初始state?描述: getInitialState(){ return {data:[]}; } ...

  5. React中setState学习总结

    react中setState方法到底是异步还是同步,其实这个是分在什么条件下是异步或者同步. 1.先来回顾一下react组件中改变state的几种方式: import React, { Compone ...

  6. React的setState学习及应用

    React的setState学习及应用 一:作用: setState() 将对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件.这是用于更新 ...

  7. React 的setState 理解

    我们都知道在React中,setState() 方法是用来改变组件状态的,在项目中也一直用,也没有出现什么问题(使用方法太简单了),但今天看了一篇文章,提到了setState 使用时的两个注意点,加深 ...

  8. react中setState用法

    setState()更新状态的2种写法 setState(updater, [callback]), updater为返回stateChange对象的函数: (state, props) => ...

  9. React中setState 什么时候是同步的,什么时候是异步的?

    class Example extends React.Component { constructor() { super(); this.state = { val: 0 }; } componen ...

随机推荐

  1. LCA:倍增与tarjan

    学了好久(一两个星期)都没彻底搞懂的lca,今天总算理解了.就来和大家分享下我自己的心得 首先,如果你还不懂什么是lca,出门左转自行百度 首先讲倍增 倍增的思想很简单,首先进行预处理,用一个深搜将每 ...

  2. 虚拟环境中pip install requirments.txt: Cannot fetch index base URL https://pypi.python.org/simple/

    Stackoverflow  : http://stackoverflow.com/questions/15501133/python-pip-error-cannot-fetch-index-bas ...

  3. 【BZOJ 2665】 2665: [cqoi2012]编号(暴力?)

    2665: [cqoi2012]编号 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 347  Solved: 217 Description 你需要给一 ...

  4. 【BZOJ 3809】 3809: Gty的二逼妹子序列 (莫队+分块)

    3809: Gty的二逼妹子序列 Time Limit: 80 Sec  Memory Limit: 28 MBSubmit: 1728  Solved: 513 Description Autumn ...

  5. [USACO06FEC]Milk Patterns --- 后缀数组

    [USACO06FEC]Milk Patterns 题目描述: Farmer John has noticed that the quality of milk given by his cows v ...

  6. [BZOJ4196][NOI2015]软件包管理器(树链剖分)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2166  Solved: 1253[Submit][Sta ...

  7. Android UI框架基本概念

    Activity:基本的页面单元,Activity包含一个Window,window上可以绘制各种view View:最基本的UI组件,表示屏幕上的一个矩形区域: Window:表示顶层窗口,管理界面 ...

  8. redis的原子性

    什么是原子性操作 在多进程(线程)访问共享资源时,能够确保所有其他的进程(线程)都不在同一时间内访问相同的资源,(要么完全执行,要么完全不执行) 简单描述 有个变量X=0,要进行+1操作,步骤如下: ...

  9. css选择器:first-child和nth-child 采坑记

    今天想用nth-child来给一个类似于树的目录(bootstrap-nav-tree  一个angularjs插件)设置不同的颜色,结构大致类似于 <ul> <li class=& ...

  10. python string和dict转换

    字典(dict)转为字符串(string) 我们可以比较容易的将字典(dict)类型转为字符串(string)类型. 通过遍历dict中的所有元素就可以实现字典到字符串的转换: for key, va ...