Best way to access context from ContextProviders #3316
Replies: 5 comments 3 replies
-
The current approach is by design. If you need to use contexts with struct components, you need to define a callback and hold the context handle. Without subscribing to a context, the component will not be notified for any updates. This results in inconsistency in your application. The current approach forces struct component users to define a callback so context updates can be sent to struct components. If you want less boilerplate, you should consider using function components. |
Beta Was this translation helpful? Give feedback.
-
Code would look quite similar, but you only need to store the ContextObserver in your state (which stores both value and handle). ...
pub enum Msg {
ContextUpdated,
}
pub struct StructComponentSubscriber {
message_context: ContextObserver<MessageContext>,
}
impl Component for StructComponentSubscriber {
type Message = Msg;
type Properties = ();
fn create(ctx: &Context<Self>) -> Self {
let message_context = ContextObserver::new(ctx.link())
.on_change(ctx.link().callback(|_| Msg::ContextUpdated));
Self {
message_context,
}
}
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::ContextUpdated => { true } // just redraw
}
}
fn view(&self, _ctx: &Context<Self>) -> Html {
let message = match self.message_context.get() {
Some(message_context) => message_context.inner.to_string(),
None => String::from("No message context provided"),
};
html! {
<h1>{ message }</h1>
}
}
} |
Beta Was this translation helpful? Give feedback.
-
As noted by other answers, you should connect to the context in your pub struct StructComponentSubscriber {
message_context: ContextHolder<MessageContext>,
}
impl Component for StructComponentSubscriber {
type Properties = ();
fn create(ctx: &Context<Self>) -> Self {
// We can internally hold the found Scope<ContextProvider<MessageContext>> and deref/clone
// the context value on demand in view (no other component should have a MutRef to that provider's state there)
// We know which component to re-render from the ctx
let message_context = ctx.with_context::<MessageContext>(|new_ctx| {
let should_rerender = todo!();
should_rerender
});
Self {
message_context,
}
}
fn view(&self, _ctx: &Context<Self>) -> Html {
let message = match self.message_context.get() {
Some(message_context) => message_context.inner.to_string(),
None => String::from("No message context provided"),
};
html! {
<h1>{ message }</h1>
}
}
} |
Beta Was this translation helpful? Give feedback.
-
Sorry, but this is exactly what I am doing (connect to the context in the create method). Of cause, a way to avoid sending a message for re-render can be convenient. On the other side you sometimes need the Anyways, the code I posted I a slightly modified version of what we have in the "use_context()" hook. So it would be possible to use the same code in the hook and in struct components. |
Beta Was this translation helpful? Give feedback.
-
It is quite ease to access a context from function components, i.e:
But it is quite clumsy inside a Component impl.
Is there an easier way to get the context?
Beta Was this translation helpful? Give feedback.
All reactions