【问题标题】:Circular app context dependency with React Context使用 React Context 的循环应用程序上下文依赖
【发布时间】:2021-07-13 09:17:22
【问题描述】:

我有两个钩子,useAuseB,它们执行昂贵的操作(假设网络 API 调用)并且这些值需要使用 React 的 Context API 保存到全局应用程序状态 (AppContext)。此外,第二个钩子 useB 的行为取决于第一个钩子 useA 的结果。

一旦启动应用程序并创建上下文提供程序,就会调用这些挂钩。我在上下文提供程序组件中调用钩子,并在第二个钩子中使用相同的上下文。这会产生导致信息陈旧的问题; useContext(AppContext) 内的 useB 没有为 useA 提供正确的结果。因为useA 的结果需要在useB 钩子的上下文之外,所以我不能将它的调用移到useB 钩子下。否则,这将导致对useA 的两次调用,一次在上下文提供程序内部,一次在useB 内部。

如何解决这个问题?

const useA = () => {
  const api = useApi()
  const [state, setState] = useState(null)

  useEffect(() => {
    api.someFn().then((result) => {
      setState(result)
    })
  }, [api])

  return state
}

const useB = () => {
  const api = useApi()
  const { a } = useContext(AppContext)
  const [state, setState] = useState(null)

  useEffect(() => {
    api.someOtherFn(a.someVariable).then((result) => {
      setState(result)
    })
  }, [api, a])

  return state
}

const AppContext = createContext({ a: null, b: null })

const AppContextProvider = (children) => {
  const a = useA()
  const b = useB()

  const context = { a, b }

  return <AppContext.Provider value={context}>{children}</AppContext.Provider>
}

const App = () => {
  return (
    <AppContextProvider>
      <Router>
        ...
      </Router>
    </AppContextProvider>
  )
}

【问题讨论】:

    标签: reactjs react-hooks react-context


    【解决方案1】:

    也许以下会有用:

    const useA = () => {
      const api = useApi()
      const [state, setState] = useState(null)
    
      useEffect(() => {
        api.someFn().then((result) => {
          setState(result)
        })
      }, [api])
    
      return state
    }
    
    const useB = (a) => {
      const api = useApi()
      const [state, setState] = useState(null)
    
      useEffect(() => {
        if (a && a.someVariable) {
          api.someOtherFn(a.someVariable).then((result) => {
            setState(result)
          })
        }
      }, [api, a])
    
      return state
    }
    
    const AppContext = createContext({ a: null, b: null })
    
    const AppContextProvider = (children) => {
      const a = useA()
      const b = useB(a)
    
      // It is not recommended to pack several values into some object and share it via context
      // Cause consumers will be retriggered on each call to AppContextProvider
      const context = { a, b }
    
      return <AppContext.Provider value={context}>{children}</AppContext.Provider>
    }
    
    const App = () => {
      return (
        <AppContextProvider>
          <Router>
            ...
          </Router>
        </AppContextProvider>
      )
    }
    

    请阅读多个上下文https://reactjs.org/docs/context.html#consuming-multiple-contexts

    【讨论】:

      猜你喜欢
      • 2010-10-28
      • 1970-01-01
      • 2010-11-20
      • 2011-06-14
      • 2012-07-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-17
      • 2021-11-14
      相关资源
      最近更新 更多