edifice.use_callback#
- edifice.use_callback(fn, dependencies)[source]#
Hook for a callback function to pass as props.
This Hook behaves like React useCallback.
Use this Hook to reduce the re-render frequency of a
@component
which has a prop that is a function.This Hook will return a callback function with specific bound
dependencies
and the callback function will only change when the specifieddependencies
are not__eq__
to thedependencies
from the last render, so the callback function can be used as a stable prop.The problem#
We want to present the user with a hundred buttons and give the buttons an
on_click
prop.This
SuperComp
component will re-render every time thefastprop
prop changes, so then we will have to re-render all the buttons even though the buttons don’t depend on thefastprop
.@component def SuperComp(self, fastprop:int, slowprop:int): value, value_set = use_state(0) def value_from_slowprop(): value_set(slowprop) for i in range(100): Button( on_click=lambda _event: value_from_slowprop() )
The general solution to this kind of performance problem is to create a new
@component
to render the buttons. This newButtons100
@component
will only re-render when itsclick_handler
prop changes.@component def Buttons100(self, click_handler:Callable[[], None]): for i in range(100): Button( on_click=lambda _event: click_handler() ) @component def SuperComp(self, fastprop:int, slowprop:int): value, value_set = use_state(0) def value_from_slowprop(): value_set(slowprop) Buttons100(value_from_slowprop)
But there is a problem here, which is that the
click_handler
prop for theButtons100
component is a new functionvalue_from_slowprop
every time that theSuperComp
component re-renders, so it will always cause theButtons100
to re-render.We can’t define
value_from_slowprop
as a constant function declared outside of theSuperComp
component because it depends on bindings toslowprop
andvalue_set
.The solution#
So we use the
use_callback()
Hook to create a callback function which only changes whenslowprop
changes.And now the
Buttons100
will only re-render when theslowprop
changes.The
value_set
setter function does not need to be in thedependencies
because each setter function is always__eq__
from the previous render.@component def Buttons100(self, click_handler:Callable[[], None]): for i in range(100): Button( on_click=lambda _event: click_handler(), ) @component def SuperComp(self, fastprop:int, slowprop:int): value, value_set = use_state(0) def make_value_from_slowprop(): def value_from_slowprop(): value_set(slowprop) return value_from_slowprop value_from_slowprop = use_callback( make_value_from_slowprop, (slowprop,), ) Buttons100(value_from_slowprop)
- type fn:
Callable
[[],Callable
[[ParamSpec
(_P_callback
)],None
]]- param fn:
A function of no arguments which creates and returns a callback function.
- type dependencies:
Any
- param dependencies:
The callback function will be created when the
dependencies
are not__eq__
to the olddependencies
.- rtype:
Callable
[[ParamSpec
(_P_callback
)],None
]- returns:
A callback function.