Performance overview

Performance is one of the main goals of the Hookstate project alongside with simple and flexible API. Hookstate has got two technologies built-in, which make it stand out and deliver incredible performance for applications:

  1. Hookstate does usage tracking to identify what components require rerendering when a state is changed. It is possible to disable this with help of Downgraded plugin on per component basis or per state.
  2. Hookstate has got scoped state feature which multiplies the effect of the first, particularly for the cases involving large states and frequent updates.

The following matrix explains the effect of usage tracking and scoped states. Code samples are below as well.

Legend:

  • Y - component rerenders on state change
  • N - component does not rerender on state change
  • P - component rerenders because the parent is rerendered

State:

const globalState = createState({ A: 0, B: 0 })

Actions:

const setA = () => globalState.A.set(p => p + 1)
const setB = () => globalState.B.set(p => p + 1)
const mergeA = () => globalState.merge(p => ({ A: p.A + 1 }))
const mergeB = () => globalState.merge(p => ({ B: p.B + 1 }))
const mergeAB = () => globalState.merge(p => ({ A: p.A + 1, B: p.B + 1 }))
const setObj = () => globalState.set(p => ({ ...p, A: p.A + 1 }))
rerender on actions:setA
mergeA
setB
mergeB
mergeABsetObj
Ex1_Parent_GlobalStateNotHookedNNNN
Ex1_Child_GlobalStateHooked_AUsedYNYY
Ex1_Child_GlobalStateHooked_BUsed_DowngradedYYYY
Ex2_Parent_GlobalStateHookedYYYY
Ex2_Child_PropsState_AUsedPPPP
Ex2_Child_PropsState_BUsed_DowngradedPPPP
Ex3_Parent_GlobalStateHookedNNNY
Ex3_Child_PropsState_AUsed_ScopedYNYP
Ex3_Child_PropsState_BUsed_Scoped_DowngradedNYYP
Ex4_Parent_GlobalStateHookedNYYY
Ex4_Child_PropsState_AUsed_ScopedYPPP
Ex4_Child_PropsState_BUsedNPPP
Ex5_Component_GlobalStateHooked_NotUsedNNNN
Ex6_Component_GlobalStateHooked_ObjUsedNNNY
Ex7_Component_GlobalStateHooked_KeysUsedYYYY

Example 1: Children hook the state, but the parent does not.

function Ex1_Parent_GlobalStateNotHooked() {
return <>
<Ex1_Child_GlobalStateHooked_AUsed />
<Ex1_Child_GlobalStateHooked_BUsed_Downgraded />
</>
}
function Ex1_Child_GlobalStateHooked_AUsed() {
const state = useState(globalState)
return <p>{state.A.value}</p>
}
function Ex1_Child_GlobalStateHooked_BUsed_Downgraded() {
const state = useState(globalState)
state.attach(Downgraded)
return <p>{state.B.value}</p>
}

Example 2: The parent hooks the state and passes nested to children. Children do NOT USE scoped state

function Ex2_Parent_GlobalStateHooked() {
const state = useState(globalState)
return <>
<Ex2_Child_PropsState_AUsed state={state.A}/>
<Ex2_Child_PropsState_BUsed_Downgraded state={state.B}/>
</>
}
function Ex2_Child_PropsState_AUsed(props: { state: State<number> }) {
const state = props.state
return <p>{state.value}</p>
}
function Ex2_Child_PropsState_BUsed_Downgraded(props: { state: State<number> }) {
const state = props.state
state.attach(Downgraded)
return <p>{state.value}</p>
}

Example 3: The parent hooks the state and passes nested to children. Children USE scoped state.

function Ex3_Parent_GlobalStateHooked() {
const state = useState(globalState)
return <>
<Ex3_Child_PropsState_AUsed_Scoped state={state.A}/>
<Ex3_Child_PropsState_BUsed_Scoped_Downgraded state={state.B}/>
</>
}
function Ex3_Child_PropsState_AUsed_Scoped(props: { state: State<number> }) {
const state = useState(props.state)
return <p>{state.value}</p>
}
function Ex3_Child_PropsState_BUsed_Scoped_Downgraded(props: { state: State<number> }) {
const state = useState(props.state)
state.attach(Downgraded)
return <p>{state.value}</p>
}

Example 4: The parent hooks the state and passes nested to children. Once child USES scoped state, another does NOT.

function Ex4_Parent_GlobalStateHooked() {
const state = useState(globalState)
return <>
<Ex4_Child_PropsState_AUsed_Scoped state={state.A}/>
<Ex4_Child_PropsState_BUsed state={state.B}/>
</>
}
function Ex4_Child_PropsState_AUsed_Scoped(props: { state: State<number> }) {
const state = useState(props.state)
return <p>{state.value}</p>
}
function Ex4_Child_PropsState_BUsed(props: { state: State<number> }) {
const state = props.state
return <p>{state.value}</p>
}

Example 5: A component hooks the state but does not use it.

function Ex5_Component_GlobalStateHooked_NotUsed() {
const state = useState(globalState)
return <></>
}

Example 6: A component hooks the state and uses only an object without reading it's properties.

function Ex6_Component_GlobalStateHooked_ObjUsed() {
const state = useState(globalState)
const unused = state.value
return <></>
}

Example 7: A component hooks the state and uses object's keys.

function Ex7_Component_GlobalStateHooked_KeysUsed() {
const state = useState(globalState)
const unused = state.keys
return <></>
}