Update React Context using a REST Api call in a functional component

First thing that I am seeing is that you are not returning the promise within your function which will lead to setting the state to undefined.

I added the return statement below:

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

Also your last then-chain could be cleaned up a bit and I am quite sure you can remove the await statement in an async function when returning a promise. It will automatically be awaited:

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

Second step would be to have a look at your useEffect hook. You want to setText after the promise from the api call has been resolved. So you have to make the callback function of useEffect asynchronous as well.

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

Third step, would be to look at how to properly use the context api and the useContext hook. The useContext hook takes a context as a parameter but you passed the ContextProvider as the argument.

const text = useContext(TextContext);

The context and the context-provider are two different entities in the React world. Think of the context as state and functionality that you want to share across your application (like a global state), and think about the provider as a react component that manages one context and offers this context state to it's child components.

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

This is how a return statement of a provider component would look like and I think this code is currently missing in your application.


You have a lot of problems here. fetching and changing should happen inside Provider by modifying the value property. useContext receives an entire Context object not only the Provider. Check the following

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

Now inside your 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>
   )
}

Now you have a Provider that fetches some data and pass it down inside value prop. To consume it from inside a functional component use useContext like this

import { context } from './Context'

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

    return <SomeJSX />
}

Remember that Component must be under MyProvider

UPDATE

  • What is { children }?

Everything that goes inside a Component declaration is mapped to props.children.

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

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

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

Declaring it like ({ children }) it's just a shortcut to const { children } = props. I'm using children so that you can use your Provider like this

<MyProvider>
    <RestOfMyApp />
</MyProvider>

Here children is RestOfMyApp

  • How do I access the value of the Provider inside the Profile.js?

Using createContext. Let's assume the value property of your Provider is {foo: 'bar'}

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

    console.log(content) //{ foo : 'bar' }
}
  • How can you double declare a constant as you've done in the Provider?

That was a typo, I've changed to MyProvider

To access it from inside a class based component

class Component extends React.Component{
    render(){
        const { Consumer } = context
        return(
             <Consumer>
                 {
                     context => console.log(contxt) // { foo: 'bar' }
                 }
             </Consumer>
        )
    }
}