Skip to content

Commit a70ed0f

Browse files
committed
implement use_context hook
1 parent 545f2f1 commit a70ed0f

File tree

10 files changed

+621
-94
lines changed

10 files changed

+621
-94
lines changed

docs/source/reference-material/hooks-api.rst

+21-3
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,9 @@ There are **three important subtleties** to note about using asynchronous effect
186186
Manual Effect Conditions
187187
........................
188188

189-
In some cases, you may want to explicitely declare when an effect should be triggered.
190-
You can do this by passing ``dependencies`` to ``use_effect``. Each of the following values
191-
produce different effect behaviors:
189+
In some cases, you may want to explicitly declare when an effect should be triggered.
190+
You can do this by passing ``dependencies`` to ``use_effect``. Each of the following
191+
values produce different effect behaviors:
192192

193193
- ``use_effect(..., dependencies=None)`` - triggers and cleans up on every render.
194194
- ``use_effect(..., dependencies=[])`` - only triggers on the first and cleans up after
@@ -197,6 +197,24 @@ produce different effect behaviors:
197197
``x`` or ``y`` have changed.
198198

199199

200+
Use Context
201+
-----------
202+
203+
.. code-block::
204+
205+
value = use_context(MyContext)
206+
207+
Accepts a context object (the value returned from
208+
:func:`idom.core.hooks.create_context`) and returns the current context value for that
209+
context. The current context value is determined by the ``value`` argument passed to the
210+
nearest ``MyContext`` in the tree.
211+
212+
When the nearest <MyContext.Provider> above the component updates, this Hook will
213+
trigger a rerender with the latest context value passed to that MyContext provider. Even
214+
if an ancestor uses React.memo or shouldComponentUpdate, a rerender will still happen
215+
starting at the component itself using useContext.
216+
217+
200218
Supplementary Hooks
201219
===================
202220

src/idom/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
from .core.dispatcher import Stop
55
from .core.events import EventHandler, event
66
from .core.hooks import (
7+
create_context,
78
use_callback,
9+
use_context,
810
use_effect,
911
use_memo,
1012
use_reducer,
@@ -28,6 +30,7 @@
2830
"Component",
2931
"ComponentType",
3032
"config",
33+
"create_context",
3134
"event",
3235
"EventHandler",
3336
"hooks",
@@ -42,6 +45,7 @@
4245
"run",
4346
"Stop",
4447
"use_callback",
48+
"use_context",
4549
"use_effect",
4650
"use_memo",
4751
"use_reducer",

src/idom/core/_thread_local.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from threading import Thread, current_thread
2+
from typing import Callable, Generic, TypeVar
3+
from weakref import WeakKeyDictionary
4+
5+
6+
_StateType = TypeVar("_StateType")
7+
8+
9+
class ThreadLocal(Generic[_StateType]):
10+
"""Utility for managing per-thread state information"""
11+
12+
def __init__(self, default: Callable[[], _StateType]):
13+
self._default = default
14+
self._state: WeakKeyDictionary[Thread, _StateType] = WeakKeyDictionary()
15+
16+
def get(self) -> _StateType:
17+
thread = current_thread()
18+
if thread not in self._state:
19+
state = self._state[thread] = self._default()
20+
else:
21+
state = self._state[thread]
22+
return state
23+
24+
def set(self, state: _StateType) -> None:
25+
self._state[current_thread()] = state

src/idom/core/component.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
def component(
1111
function: Callable[..., Union[ComponentType, VdomDict | None]]
12-
) -> Callable[..., "Component"]:
12+
) -> Callable[..., Component]:
1313
"""A decorator for defining a new component.
1414
1515
Parameters:
@@ -54,6 +54,9 @@ def __init__(
5454
def render(self) -> VdomDict | ComponentType | None:
5555
return self.type(*self._args, **self._kwargs)
5656

57+
def should_render(self, new: Component) -> bool:
58+
return True
59+
5760
def __repr__(self) -> str:
5861
try:
5962
args = self._sig.bind(*self._args, **self._kwargs).arguments

0 commit comments

Comments
 (0)