Basic Usage with React
work in progress
Fetching sync and async dependencies from ITI in React is conceptually similar to data fetching. If you’ve used libraries like React Query, swr, Apollo Client or similar this will feel familiar.
Data fetching
Section titled “Data fetching”import useSWR from "swr"
function Profile() { const { data, error } = useSWR("/api/user", fetcher)
if (error) return <div>failed to load</div> if (!data) return <div>loading...</div> return <div>hello {data.name}!</div>}
import { QueryClient, QueryClientProvider, useQuery } from "react-query"import axios from "axios"
export function Profile() { const { isLoading, error, data, isFetching } = useQuery("userData", () => axios.get("/api/user").then((res) => res.data) )
if (isLoading) return "Loading..." if (error) return "An error has occurred: " + error.message
return <div>hello {data.name}!</div>}
import { gql, useQuery } from "@apollo/client"
const GET_PROFILE_QUERY = gql` query GetProfile { profile { id name } }`
function Profile() { const { loading, error, data } = useQuery(GET_PROFILE_QUERY)
if (loading) return "Loading..." if (error) return `Error! ${error.message}`
return <div>hello {data.name}!</div>}
Async Request for single item in ITI
Section titled “Async Request for single item in ITI”import { useContainer } from "./_containers/main-app"
function Profile() { const [auth, authErr] = useContainer().auth
if (authErr) return <div>failed to load</div> if (!auth) return <div>loading...</div>
return <div>hello {auth.profile.name}!</div>}
Async Request for multiple items
Section titled “Async Request for multiple items”useContainerSet
import { useContainer, useContainerSet } from "./_containers/main-app"
// Callback style
function Profile() { const [profileDeps, profileDepsErr] = useContainerSet((c) => [c.auth, c.env])
if (!profileDeps || profileDepsErr) return null const { auth, env } = profileDeps
return <div>hello {auth.profile.name}!</div>}
// Literal stylefunction Profile() { const [profileDeps, profileDepsErr] = useContainerSet(["auth", "env"])
if (!profileDeps || profileDepsErr) return null const { auth, env } = profileDeps
return <div>hello {auth.profile.name}!</div>}
Ensure Sync Containers
Section titled “Ensure Sync Containers”You might want a simpler API for your components
So we could go
From:
const [profileDeps, profileDepsErr] = useContainerSet(["auth", "env"])if (!profileDeps || profileDepsErr) return null
To:
const { auth, env } = useProfileDeps()
To achieve that we will have to create a wrapping component. Very similar to React.Suspense
// This component is loaded dynamicallyconst OtherComponent = React.lazy(() => import("./OtherComponent"))
function MyComponent() { return ( // Displays <Spinner> until OtherComponent loads <React.Suspense fallback={<Spinner />}> <div> <OtherComponent /> </div> </React.Suspense> )}
We will create a wrapping component that will fetch dependencies, provide fallback and provide context for nested components
import React, { useContext } from "react"import { generateEnsureContainerSet } from "iti-react"import { useContainerSet } from "./_editor-app-hooks"
const x = generateEnsureContainerSet(() => useContainerSet(["ecommerce", "auth"]))export const EnsureEcommerceContainer = x.EnsureWrapperexport const useEcommerceContext = x.contextHook
import { EnsureEcommerceContainer } from "./_containers-react/EnsureEcommerce"
export const App = () => ( <div className="App"> <EnsureEcommerceContainer fallback={<>Loading</>}> <MainApp /> </EnsureEcommerceContainer> </div>)
import { useEcommerceContext } from "../../../../_containers-react/EnsureEcommerce"
export const CurrencyInfo = () => { const { currencyStore, taxStore } = useEcommerceContext().ecommerce
return <div>{currencyStore.currency}</div>}