Replies: 1 comment
-
This is with yew v0.18, assuming that's the version you are using! use anyhow::Error;
use serde::{Deserialize, Serialize};
use yew::{
format::Json,
prelude::*,
services::{
fetch::{FetchTask, Request, Response},
FetchService,
},
};
// This Model can be anything you want just make sure it can derive Serialize
#[derive(Serialize)]
struct Model {
data: usize,
}
// This Model can be anything you want just make sure it can derive Deserialize
#[derive(Deserialize)]
struct ResponseModel {
data: usize,
}
struct MyDataType {
endpoint: String,
model: Model,
}
fn upload<OUT, T>(
data: MyDataType,
link: ComponentLink<T>,
to_msg: impl Fn(OUT) -> T::Message + 'static,
) -> FetchTask
where
T: Component,
Json<OUT>: From<Result<String, Error>> + 'static,
{
let post_request = Request::post(format!("/api/up/{}", data.endpoint))
.header("Content-Type", "application/json")
.body(Json(&data.model))
.expect("Could not build that request.");
let callback = link.batch_callback(move |response: Response<Json<OUT>>| {
let (meta, Json(data)) = response.into_parts();
if meta.status.is_success() {
Some(to_msg(data))
} else {
// probably want to do better error handling here then this
None
}
});
FetchService::fetch(post_request, callback).unwrap()
}
pub struct Comp {
link: ComponentLink<Self>,
fetch_task: Option<FetchTask>,
}
pub enum Msg {
FetchReady(Result<ResponseModel, Error>),
}
impl Component for Comp {
type Message = Msg;
type Properties = ();
fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
let model = Model { data: 20 };
let data_type = MyDataType {
endpoint: "endpoint".to_owned(),
model,
};
let fetch_task = upload(data_type, link.clone(), Msg::FetchReady);
let fetch_task = Some(fetch_task);
Self { link, fetch_task }
}
fn update(&mut self, msg: Self::Message) -> ShouldRender {
let Msg::FetchReady(resp) = msg;
match resp {
Ok(data) => {} // woo got my data
Err(er) => {} // something went wrong :(
}
true
}
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
false
}
fn view(&self) -> Html {
html! {}
}
} Hope this helps :) bit bare bones in the sense of no view but I think this shows how you can use the function in a component :D You got the error message because your function took in a generic If you wanted say only a single enum for this type of thing you could remove the pub enum FetchMsg {
Whatever,
}
fn upload<OUT, T>(
data: MyDataType,
link: ComponentLink<T>,
) -> FetchTask
where
T: Component<Message = FetchMsg>
Json<OUT>: From<Result<String, Error>> + 'static,
{
// all the same apart from the next line
// was: `Some(to_msg(data))`
Some(FetchMsg::Whatever)
} Hope this helps answer the question - if it has done please mark it as answered so others can benefit from the answer too 🥳 |
Beta Was this translation helpful? Give feedback.
-
I want to have a function like
upload
which is independent in impl from my components, which they can just invoke passing a reference to their own link.This is one usecase for functions external to components, I assume there may be other, I assume this could be handled with "mega parent component that the kids call to do anything" but this pattern is not made explicit nor endorsed by the docs.
I thought this impl would work:
However, this seems to fail with that error:
the trait 'From<Msg>' is not implemented for '<T as yew::Component>::Message'
... at which point I've got no idea what to do anymore.Any help here would be appreciated :)
For now I'm just boilperplating but as a project scales this is obvious ugly and not the way to go.
Beta Was this translation helpful? Give feedback.
All reactions