[React] Safely setState on a Mounted React Component through the useEffect Hook
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的更多相关文章
- React的setState分析
前端框架层出不穷,不过万变不离其宗,就是从MVC过渡到MVVM.从数据映射到DOM,angular中用的是watcher对象,vue是观察者模式,react就是state了. React通过管理状态实 ...
- React的setState执行机制
1. setState基本特点 1. setState是同步执行的 setState是同步执行的,但是state并不一定会同步更新 2. setState在React生命周期和合成事件中批量覆盖执行 ...
- React中setState同步更新策略
setState 同步更新 我们在上文中提及,为了提高性能React将setState设置为批次更新,即是异步操作函数,并不能以顺序控制流的方式设置某些事件,我们也不能依赖于this.state来计算 ...
- 初学React,setState后获取到的thisstate没变,还是初始state?
问题:(javascript)初学React,setState后获取到的thisstate没变,还是初始state?描述: getInitialState(){ return {data:[]}; } ...
- React中setState学习总结
react中setState方法到底是异步还是同步,其实这个是分在什么条件下是异步或者同步. 1.先来回顾一下react组件中改变state的几种方式: import React, { Compone ...
- React的setState学习及应用
React的setState学习及应用 一:作用: setState() 将对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件.这是用于更新 ...
- React 的setState 理解
我们都知道在React中,setState() 方法是用来改变组件状态的,在项目中也一直用,也没有出现什么问题(使用方法太简单了),但今天看了一篇文章,提到了setState 使用时的两个注意点,加深 ...
- react中setState用法
setState()更新状态的2种写法 setState(updater, [callback]), updater为返回stateChange对象的函数: (state, props) => ...
- React中setState 什么时候是同步的,什么时候是异步的?
class Example extends React.Component { constructor() { super(); this.state = { val: 0 }; } componen ...
随机推荐
- git clone https
git clone 不需要输入密码步骤 1, vim ~/.git-credentials 2, git config --global credential.helper store 3, vim ...
- vue 阻止表单默认事件
方式一: <form autocomplete="off" @submit.prevent="onSubmit"> <input type=& ...
- 利用gmpy2破解rsa
gmpy2的相关文档: https://gmpy2.readthedocs.io/en/latest/ ================ 题目: 来自实验吧的rsarsa:http://www.shi ...
- bzoj4556: [Tjoi2016&Heoi2016]字符串 (后缀数组加主席树)
题目是给出一个字符串,每次询问一个区间[a,b]中所有的子串和另一个区间[c,d]的lcp最大值,首先求出后缀数组,对于lcp的最大值肯定是rank[c]的前驱和后继,但是对于这个题会出现问题,就是题 ...
- [BZOJ3924][ZJOI2015]幻想乡战略游戏(动态点分治)
题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打 ...
- Ajax 跨域问题(JSONP && Access-Control-Allow-Origin)
1.使用jsonp跨域请求 2.通过设置服务端头部跨域请求 3.设置nginx/apach 使用jsonp跨域请求 什么是Jsonp JSONP(JSON with Padding)是一个非官方的协议 ...
- bzoj 3172: [Tjoi2013]单词 AC自动机
3172: [Tjoi2013]单词 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...
- Bayesian Face Revisited A Joint Formulation
很有意思的一篇人脸识别算法文章,人家写的太好,就不好意思写了,收集了一些资料,包括了原理介绍,流程图,项目网址和作者主页信息等. 参考资料: [1]. http://blog.csdn.net/csy ...
- AJAX传递数组
在前台中Jq代码中中用JSON.stringify()将数组转换成 JSON字符串.在后台用json_decode()将JSON字符串转换成数组. 1.JSON.stringify(value [, ...
- Use a microcontroller to design a boost converter
Boost converters, like other switchers, have traditionally received their control signals from a ded ...