Context

  • Context provides a way to share values between components in a component tree
  • Drawback: it renders all the components under the provider each time the context state changes
    • Should use React.memo for components within the provider
module FunContext = {
  let context = React.createContext("")

  module Provider = {
    let provider = React.Context.provider(context)
    @react.component
    let make = (~value, ~children) => {
      React.createElement(provider, {"value": value, "children": children})
    }
  }
}

module Component1 = {
  @react.component
  let make = () => {
    let fun = React.useContext(FunContext.context)
    <div className="flex flex-col items-center justify-center">
      <div> {Js.Date.now()->React.float} </div>
      {React.string(fun)}
    </div>
  }
  let make = React.memo(make) // Foo won't render when provider state changes
}
module Component2 = {
  @react.component
  let make = () => {
    <div className="flex flex-col items-center justify-center">
      <div> {Js.Date.now()->React.float} </div>
      <Component1 />
    </div>
  }
  let make = React.memo(make) // Foo won't render when provider state changes
}
module Component3 = {
  @react.component
  let make = () => {
    <div className="flex flex-col items-center justify-center">
      <div> {Js.Date.now()->React.float} </div>
      <Component2 />
    </div>
  }
  let make = React.memo(make) // Component 3 will be rerendered cause of the state changes
}

module Foo = {
  @react.component
  let make = () => {
    <div className="flex items-center justify-center">
      <span> {"Foo "->React.string} </span>
      <div> {Js.Date.now()->React.float} </div>
    </div>
  }
  let make = React.memo(make) // Foo won't render when provider state changes
}

@react.component
let make = () => {
  let (fun, setFun) = React.useState(_ => "fun")
  <FunContext.Provider value={fun}>
    <div className="flex flex-col items-center justify-center">
      <Component3 />
      <button type_="button" className="bg-300 p-2" onClick={_ => setFun(prev => prev ++ prev)}>
        {"Have Fun"->React.string}
      </button>
    </div>
    <Foo />
  </FunContext.Provider>
}