[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
相关文章
- Error This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. T
- Call to master/192.168.137.101:9001 failed on connection exception: java.net.ConnectException: Connection refused
- [React] Using react-styleguidist for Component demo
- [React Testing] Test your Custom Hook Module with react-hooks-testing-library
- [React Testing] Test Drive Mocking react-router’s Redirect Component on a Form Submission
- [React] Create a Virtualized List with Auto Sizing Cells using react-virtualized and CellMeasurer
- [React] useEffect - problem: depending On State Mutated In The useEffect
- [React] Update State Based on Props using the Lifecycle Hook getDerivedStateFromProps in React16.3
- [React Intl] Render Content with Markup Using react-intl FormattedHTMLMessage
- [React Intl] Render Content with Placeholders using react-intl FormattedMessage
- [React] React Fundamentals: Add-on ClassSet() for ClassName
- Flink(6):Flink安装部署之Flink On Yarn模式
- Spark on k8s提交测试任务失败报错解决办法:User “system:serviceaccount:default:default“ cannot get resource “pods
- spark on k8s准确完整的测试步骤:提交Pi计算程序至k8s集群
- AndroidStudio3.0 注解报错Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor.
- atitit.React 优缺点 相比angular react是最靠谱的web ui组件化方案了
- atitit.React 优缺点 相比angular react是最靠谱的web ui组件化方案了
- Paper:LSTM之父眼中的深度学习十年简史《The 2010s: Our Decade of Deep Learning / Outlook on the 2020s》的解读
- 如何在 Ubuntu 22.04 上安 Firefox.Deb(不是How to Install Firefox as a .Deb on Ubuntu 22.04 (Not a Snap)
- The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path
- 【文献学习】A Study of Transmission Characteristic on OFDM Signals Over Random and Time-Varying Meta-surfa
- React(二)react脚手架的搭建
- react源码分析:深度理解React.Context