Making API calls for Context data

Hello Everyone,
I am learning how to use the React Context API in Rescript. Towards this I wrote this code in a file called Context.res

let context = React.createContext("test")
// wrapped in provider so that we can use this as an element
module Provider = {
  let make = React.Context.provider(context)
}
// encapsulates the context object.
let useGlobalContext = () => {
  React.useContext(context)
}

Now I am using this Context like this in my main application

switch ReactDOM.querySelector("#main") {
| Some(rootElement) => 
  ReactDOM.Client.Root.render(
    ReactDOM.Client.createRoot(rootElement), 
    <React.StrictMode>
      <Context.Provider value="Hello World">
        <App />
      </Context.Provider>
    </React.StrictMode>
  )
| None => Js.Console.log("Could not find the main div")
}

This is working very well and all the components inside of App are able to read the Context using my useGlobalContext method. But the Hello world message is hard-coded.

I tried to use “useEffect” which the document says is the standard method to make API calls in react. but it always fails and it says that useEffect can only be used inside of components and my Index.res is not a react component.

So I tried to write a method like this

let getUser = async () => {
  open Fetch
  let response = await get("https://randomuser.me/api/")
  await response->Response.json -> Js.Json.stringifyAny->Belt.Option.getExn
}

and now try to use it as

      <Context.Provider value={User.getUser()}>
        <App />
      </Context.Provider>

but now the compiler complains that the method returns promise and I need string.

So it seems I cannot use useEffect and I cannot force the promise to resolve because I guess it “turtles all the way down”?

Edit:: I also tried

User.getUser() -> Js.Promise2.then(user => {
  switch ReactDOM.querySelector("#main") {
  | Some(rootElement) => 
    ReactDOM.Client.Root.render(
      ReactDOM.Client.createRoot(rootElement), 
      <React.StrictMode>
        <Context.Provider value={user}>
          <App />
        </Context.Provider>
      </React.StrictMode>
    )
  | None => Js.Console.log("Could not find the main div")
  }
})

OK I tried a little more and got the code to work (surprisingly). Although I feel that my code may be wrong and is just working accidentally

open Js.Promise2
User.getUser() -> then(user => {
  Js.Console.log(user)
  switch ReactDOM.querySelector("#main") {
  | Some(rootElement) => 
    ReactDOM.Client.Root.render(
      ReactDOM.Client.createRoot(rootElement), 
      <React.StrictMode>
        <Context.Provider value={user}>
          <App />
        </Context.Provider>
      </React.StrictMode>
    ) -> resolve
  | None => 
    Js.Console.log("Could not find the main div") -> resolve
  }
}) -> ignore

and my code to make the API call looks like

let getUser = ()  => {
  open Fetch
  open Js.Promise2
  let response = get("https://randomuser.me/api/")
   response -> then ( j => j -> Response.json) -> then (json => {
    switch json -> Js.Json.stringifyAny {
    | Some (x) => 
      resolve(x)
    | None => 
      Js.Console.log("no object")
      resolve("")
    }
   })
}```

is my code correct?

You could always turn it into a component.

For example:

module Root = {
  @react.component
  let make = () => {
    let (state, dispatch) = React.useReducer(...)

    React.useEffect(() => /* getUser */)

    switch state {
    | NotAsked | Loading => <Spinner />
    | Err(e) => <Error error={e} />
    | Data(user) =>
      <UserContext.Provider value={user}> 
        <MyApp /> 
      </UserContext.Provider>
    }
  }
}
switch ReactDOM.querySelector("#main") {
| Some(rootElement) => 
  ReactDOM.Client.Root.render(
    ReactDOM.Client.createRoot(rootElement), 
    <React.StrictMode>
        <Root />
    </React.StrictMode>
  )
| None => Js.Console.log("Could not find the main div")
}