使用功能组件中的REST Api调用更新React Context

时间:2019-09-12 12:50:14

标签: reactjs react-context

我正在尝试使用后端对REST API的API调用产生的数据来更新React App的上下文。问题是我无法同步功能。

我已经尝试过此博客文章https://medium.com/@__davidflanagan/react-hooks-context-state-and-effects-aa899d8c8014中建议的解决方案,但不适用于我的情况。

这是textContext.js的代码

import React, {useEffect, useState} from "react";
import axios from "axios";

var text = "Test";

fetch(process.env.REACT_APP_TEXT_API)
    .then(res => res.json())
    .then(json => {
      text = json;
    })




const TextContext = React.createContext(text);
export const TextProvider = TextContext.Provider;
export const TextConsumer = TextContext.Consumer;

export default TextContext

这是我尝试从上下文访问数据的功能组件

import TextProvider, {callTextApi} from "../../../../services/textService/textContext";
function  Profile()
{

  const text = useContext(TextProvider);
  console.log(text);
  const useStyles = makeStyles(theme => ({
    margin: {
      margin: theme.spacing(1)
    }
  }));

我可以在浏览器控制台的网络部分看到获取请求获取数据,但是上下文没有更新。

我尝试在textContext.js中执行此操作。

export async function callTextApi () {
  await fetch(process.env.REACT_APP_TEXT_API)
    .then(res => res.json())
    .then(json => {
      return json;
    })
}


我当时正试图使用​​useEffect函数在Profile.js中获取数据

 const [text, setText] = useState(null);
  useEffect(()=> {
    setText (callTextApi())
  },[])

这是我第一次使用React.context,这非常令人困惑。我在做错什么或想念什么?

2 个答案:

答案 0 :(得分:3)

您在这里遇到很多问题。 fetching,并且应该通过修改Provider valueproperty内部进行更改。 useContext不仅接收Context,还接收整个Provider对象。检查以下内容

//Context.js
export const context = React.createContext()

现在进入您的Provider

import { context } from './Context'

const MyProvider = ({children}) =>{
    const [data, setData] = useState(null)

    useEffect(() =>{
        fetchData().then(res => setData(res.data))
    },[])

   const { Provider } = context
   return(
       <Provider value={data}>
           {children}
       </Provider>
   )
}

现在您有一个Provider,它可以获取一些data并将其传递到value道具内。要从functional component内部使用它,请像这样使用useContext

import { context } from './Context'

const Component = () =>{
    const data = useContext(context)

    return <SomeJSX />
}

请记住,Component必须在MyProvider

更新

  • 什么是{ children }

Component声明中的所有内容都映射到props.children

const App = () =>{
    return(
        <Button>
            Title
        </Button>
    )
}

const Button = props =>{
    const { children } = props

    return(
        <button className='fancy-button'>
            { children /* Title */}
        </button>
    )
}

({ children })一样声明它只是const { children } = props的快捷方式。我正在使用children,以便您可以像这样使用Provider

<MyProvider>
    <RestOfMyApp />
</MyProvider>

这里childrenRestOfMyApp

  • 如何在Profile.js中访问提供者的值?

使用createContext。假设您的value的{​​{1}}属性为Provider

{foo: 'bar'}
  • 如何像在Provider中一样对常量进行双重声明?

那是一个错字,我改成了const Component = () =>{ const content = useContext(context) console.log(content) //{ foo : 'bar' } }

要从基于MyProvider的组件内部访问它

class

答案 1 :(得分:0)

我看到的第一件事是您没有在函数中返回promise,这将导致将状态设置为undefined。

我在下面添加了return语句:

export async function callTextApi () {
  return await fetch(process.env.REACT_APP_TEXT_API)
    .then(res => res.json())
    .then(json => {
      return json;
    })
}

也可以对您的最后一个then链进行清理,我很确定您可以在返回promise时在异步函数中删除await语句。它将自动等待:

export async function callTextApi () {
  return fetch(process.env.REACT_APP_TEXT_API)
    .then(res => res.json())
    .then(json => json)
}

第二步是查看您的useEffect钩子。您想在解决api调用的承诺后setText。因此,您还必须使useEffect的回调函数异步。

  useEffect(async ()=> {
    const newText = await callTextApi();
    setText (newText);
  },[])

第三步,将研究如何正确使用上下文api和useContext钩子。 useContext挂钩将上下文作为参数,但是您将ContextProvider传递为参数。

const text = useContext(TextContext);

上下文和上下文提供者是React世界中的两个不同实体。将上下文视为要在应用程序中共享的状态和功能(例如全局状态),并将提供者视为管理一个上下文并将此上下文状态提供给其子组件的React组件。

return(
<TextContext.Provider value={/* some value */}>
    {children}
</TextContext.Provider>);

这是提供程序组件的return语句的外观,我认为您的应用程序中目前缺少此代码。