加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

[React] Safely setState on a Mounted React Component through

发布时间:2020-12-15 20:34:16 所属栏目:百科 来源:网络整理
导读: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-flig

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,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,})

  useEffect(() => {
    if (isEqual(previousInputs.current,[query,variables])) {
      return
    }
    setState({fetching: true})
    client
      .request(query,variables)
      .then(res =>
        setState({
          data: normalize(res),loaded: true,}),)
      .catch(error =>
        setState({
          error,loaded: 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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读