The Context
object provides a way to share data between an arbitrary number
of components. Usually, data is passed from a parent to its children component,
but when we have to deal with some mostly global information, this can be
annoying, since each component will need to pass the information to each children,
even though some or most of them will not use the information.
With a Context
object, each component can subscribe (with the useContext
hook)
to its state, and will be updated whenever the context state is updated.
Assume that we have an application with various components which needs to render differently depending on the size of the device. Here is how we could proceed to make sure that the information is properly shared. First, let us create a context, and add it to the environment:
const deviceContext = new Context({ isMobile: true });
App.env.deviceContext = deviceContext;
If we want to make it completely responsive, we need to update its value whenever the size of the screen is updated:
const isMobile = () => window.innerWidth <= 768;
window.addEventListener(
"resize",
owl.utils.debounce(() => {
const state = deviceContext.state;
if (state.isMobile !== isMobile()) {
state.isMobile = !state.isMobile;
}
}, 15)
);
Then, each component that want can subscribe and render differently depending on the fact that we are in a mobile or desktop mode.
class SomeComponent extends Component {
static template = xml`
<div>
<t t-if=device.isMobile>
some simplified user interface
</t>
<t t-else="">
a more advanced user interface
</t>
</div>`;
device = useContext(this.env.deviceContext);
}
A Context
object should be created with a state object:
const someContext = new Context({ some: "key" });
Its state is now available in the state
key:
someContext.state.some = "other key";
This is the way some global code (such as the responsive code above) should
read and update the context state. However, components should not ever read the
context state directly from the context, they should instead use the useContext
hook to properly register themselves to state changes.
Note that the Context
hook is different from the React version. For example,
there is no concept of provider/consumer. So, the Context
feature does not
by itself allow the use of a different context state depending on the component
place in the component tree. However, this functionality can be obtained, if
necessary, with the use of sub environment.
The useContext
hook is the normal way for a component to register themselve
to context state changes. The useContext
method returns the context state:
device = useContext(this.env.deviceContext);
It is a simple observed state (with an owl Observer
), which contains the shared
information.