The trait bound DataResponse: IntoPropValue<std::option::Option<implicit_clone::unsync::IString>> is not satisfied in yew

hello ,
I am new to rust and I am trying to build a front-end app using yew.rs

I want to use state to show some texts in textarea that I am getting from server.
but I am getting this error
on state
here is my code :

use std::{clone, ops::Deref};

use gloo::console::log;
use reqwasm::http::Request;
use serde::{Serialize, Deserialize};
use yew::prelude::*;
use yew_router::{prelude::*,};
use crate::components::molecules::toolbar::ToolBar;

#[derive(Serialize,Deserialize,Clone)]
struct DataResponse{
    text : String
}
#[derive(Properties,PartialEq)]
pub struct Props{
    pub url:String,
}
#[function_component(Page)]
pub fn first(props:&Props)->Html{
    // let navigator = use_navigator().unwrap();
    // let onclick = Callback::from(move |_| navigator.push(&Route::Home));
    let state = use_state(||{
        DataResponse{
            text: "".to_owned()
        }
    });
    let url = props.url.clone();
    wasm_bindgen_futures::spawn_local(async move{
        let state = state.clone();
        let _url = format!("http://127.0.0.1:3000/{}",url);
        log!(&_url);
        log!("sdfasdfas");
        let response = Request::get(_url.as_str())
        .send()
        .await
        .unwrap()
        .text()
        .await
        .unwrap();
        let mut dataresponse = state.deref().clone();
        dataresponse.text = response;
        state.set(dataresponse);
        log!(&response)
                
    });
    html! {
        <>
        <div>
            <ToolBar url={props.url.clone()}/>
            <div class="container-fluid">
                <textarea name={"text"} value={*state.clone().text}>
                </textarea>
            </div>
        </div>
        </>
    }
}

and this is the exact error message on line value={state.clone()}:

the trait bound `UseStateHandle<DataResponse>: IntoPropValue<std::option::Option<implicit_clone::unsync::IString>>` is not satisfied
the following other types implement trait `IntoPropValue<T>`:
  <&'a str as IntoPropValue<StyleSource>>
  <&'static [(K, V)] as IntoPropValue<implicit_clone::unsync::IMap<K, V>>>
  <&'static [T] as IntoPropValue<implicit_clone::unsync::IArray<T>>>
  <&'static str as IntoPropValue<Classes>>
  <&'static str as IntoPropValue<implicit_clone::unsync::IString>>
  <&'static str as IntoPropValue<std::option::Option<implicit_clone::unsync::IString>>>
  <&'static str as IntoPropValue<std::option::Option<std::string::String>>>
  <&'static str as IntoPropValue<std::string::String>>
and 29 others

thank you for your help

There are two problems here.

You probably want to put parentheses around *state here, because otherwise text (a String) is dereferenced to &str, which is what the compiler complains about in the error message:

     html! {
         <>
         <div>
             <div class="container-fluid">
-                <textarea name={"text"} value={*state.clone().text}>
+                <textarea name={"text"} value={(*state).clone().text}>
                 </textarea>
             </div>
         </div>
         </>
     }

Also, you will probably encounter other errors in this code due to several variables being used after move:

  1. state is moved inside of the async block of the spawn_local call. To avoid this, the pattern that yew uses is the following:
+{
+    let state = state.clone(); // this is a local binding so the original state is not moved
     wasm_bindgen_futures::spawn_local(async move{
         let state = state.clone();
         let _url = format!("http://127.0.0.1:3000/{}",url);
         log!(&_url);
         log!("sdfasdfas");
         let response = Request::get(_url.as_str())
         .send()
         .await
         .unwrap()
         .text()
         .await
         .unwrap();
         let mut dataresponse = state.deref().clone();
+         log!(&response);
         dataresponse.text = response;
         state.set(dataresponse);
-         log!(&response)                
     });
+}
  1. I also reordered statements in the above async block because otherwise response is moved to dataresponse.text, which means that you cannot borrow it to use it in the log!(&response) statement.
1 Like

thank you so much. that first part solved my problem.
but i didn't get it completely. what is the diffrence between (*state) and *state.clone().text ?

To my understanding, the difference is that the dereference operator is not applied to the same object:

  • *state.clone().text calls state.clone(), then gets the field text, and finally derefences the field,
  • whereas (*state).clone().text dereferences state, then calls .clone() and finally gets the field text.
1 Like

so tricky! :grin:
thank you so much for your help

You're welcome!

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.