bounce 0.9.0

The uncomplicated state management library for Yew.
Documentation
#![cfg(feature = "query")]

use std::convert::Infallible;
use std::rc::Rc;
use std::time::Duration;

use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};

wasm_bindgen_test_configure!(run_in_browser);

use async_trait::async_trait;
use bounce::prelude::*;
use bounce::query::{use_query_value, Query, QueryResult};
use bounce::BounceRoot;
use gloo::timers::future::sleep;
use gloo::utils::document;
use yew::platform::spawn_local;
use yew::prelude::*;

async fn get_text_content<S: AsRef<str>>(selector: S) -> String {
    sleep(Duration::ZERO).await;

    document()
        .query_selector(selector.as_ref())
        .unwrap()
        .unwrap()
        .text_content()
        .unwrap()
}

#[test]
async fn test_query_requery_upon_state_change() {
    #[derive(PartialEq, Eq, Default, Atom)]
    pub struct MyState {
        inner: usize,
    }

    #[derive(PartialEq, Eq, Default)]
    pub struct MyQuery {
        inner: usize,
    }

    #[async_trait(?Send)]
    impl Query for MyQuery {
        type Input = ();
        type Error = Infallible;

        async fn query(states: &BounceStates, _input: Rc<()>) -> QueryResult<Self> {
            let inner = states.get_atom_value::<MyState>().inner;

            sleep(Duration::ZERO).await;

            Ok(MyQuery { inner }.into())
        }
    }

    #[function_component(Comp)]
    fn comp() -> Html {
        let my_query = use_query_value::<MyQuery>(().into());
        let set_my_state = use_atom_setter();

        use_effect_with((), move |_| {
            spawn_local(async move {
                sleep(Duration::from_millis(50)).await;

                set_my_state(MyState { inner: 1 });
            });

            || {}
        });

        match my_query.result() {
            None => {
                html! { <div id="content">{"Loading..."}</div> }
            }
            Some(Ok(m)) => {
                html! { <div id="content">{format!("value: {}", m.inner)}</div> }
            }
            Some(Err(_)) => unreachable!(),
        }
    }

    #[function_component(App)]
    fn app() -> Html {
        html! {
            <BounceRoot>
                <Comp />
            </BounceRoot>
        }
    }

    yew::Renderer::<App>::with_root(document().query_selector("#output").unwrap().unwrap())
        .render();

    let s = get_text_content("#content").await;
    assert_eq!(s, "Loading...");

    let s = get_text_content("#content").await;
    assert_eq!(s, "value: 0");

    sleep(Duration::from_millis(100)).await;

    let s = get_text_content("#content").await;
    assert_eq!(s, "value: 1");
}