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

最新文章

  1. 【系统篇】从int 3探索Windows应用程序调试原理
  2. 敏捷项目开源管理软件ScrumBasic(1)
  3. 子级与父级的margin合并的问题
  4. RxJava 和 RxAndroid 一 (基础)
  5. 【SQL Server】数据库是单个用户的 无法顺利进行操作 怎么解决
  6. android 回调函数二:应用实例
  7. 【svn】 linux svn 强制提交注释
  8. Hibernate映射解析——七种映射关系
  9. HDU4720+三角形外接圆
  10. SPOJ220 Relevant Phrases of Annihilation
  11. QT中窗口刷新事件的学习总结
  12. 发送cookie
  13. 69、django之Form组件
  14. nohup—后端守护进程
  15. Linxu指令--date,cal
  16. java调用shell脚本,并获得结果集的例子
  17. [Postman]Cookies(12)
  18. [VMWARE] [CENTOS7] 安装VMware-Tools
  19. JavaScript -- Window-状态栏
  20. java 如何对由json对象构成的数组形式的字符串进行遍历?

热门文章

  1. ZOJ 3613 Wormhole Transport
  2. php 5.6 安装openssl extension 出现编译错误
  3. 【BZOJ 3996】 3996: [TJOI2015]线性代数 (最小割)
  4. HDU 6118 度度熊的交易计划(费用流)
  5. 尝试用Gearman实现分布式处理(PHP)[转]
  6. JAVA对数字证书的常用操作(转载)
  7. UITextField设置密文延时处理---仿QQ登录密码输入
  8. spring ioc 理解
  9. jQuery Mobile 页面事件
  10. 64位系统下同时使用64位和32位的eclipse