intendednull / yewdux

Ergonomic state management for Yew applications
https://intendednull.github.io/yewdux/
Apache License 2.0
322 stars 31 forks source link

Unable to set and retrieve state. #58

Closed apoorv569 closed 1 year ago

apoorv569 commented 1 year ago

I have an Store setup called AuthStore,

use serde::{Deserialize, Serialize};
use yewdux::store::Store;

#[derive(Default, Clone, PartialEq, Store, Serialize, Deserialize)]
#[store(storage = "local")] // or session
pub struct AuthStore {
    pub username: String,
    pub password: String,
    pub is_authenticated: bool,
}

and then I use this to set values from user creation form,

use crate::{
    components::forms::create_user_form::{CreateFormStateData, CreateUserForm},
    router::Route,
    stores::auth_store::AuthStore,
};
use course_byte_shared::{create_user, NewUser, User};
use gloo::console;
use yew::{function_component, html, use_state, Callback, Html};
use yew_router::prelude::{use_navigator, Link};
use yewdux::prelude::use_store;

#[function_component(CreateUser)]
pub fn create_user() -> Html {
    let new_user_data = use_state(User::default);

    let navigator = use_navigator().unwrap();

    let (store, dispatch) = use_store::<AuthStore>();
    let dp = dispatch.clone();
    let store_c = store.clone();

    let on_submit_form = Callback::from(move |data: CreateFormStateData| {
        let new_user_data_clone = new_user_data.clone();

        let navigator_clone = navigator.clone();

        let dispatch = dispatch.clone();
        let store = store.clone();

        wasm_bindgen_futures::spawn_local(async move {
            let navigator_clone = navigator_clone.clone();

            let dispatch = dispatch.clone();
            let store = store.clone();

            match create_user(NewUser {
                username: data.username.to_string(),
                email: data.email.to_string(),
                password: data.password.to_string(),
            })
            .await
            {
                Ok(user) => {
                    let username = user.username.clone();
                    let token = user.token.clone();
                    let token_c = user.token.clone();

                    new_user_data_clone.set(user);

                    dispatch.reduce_mut(move |state| {
                        state.username = username;
                        state.password = token;
                        state.is_authenticated = true;
                    });

                    console::log!("Token: ", token_c);
                }
                Err(error) => eprintln!("API Error: {:?}", error),
            };

            // console::log!("Sucessfully created new user, redirecting to home page..");
            // navigator_clone.push(&Route::Home);
        });
    });

    html! {
        <div>
            <h1> { "Create user" } </h1>
            <CreateUserForm on_submit={ on_submit_form }/>
            // <h2> { "Username: " } { dp.get().username.clone() } </h2>
            // <h2> { "Password: " } { dp.get().password.clone() } </h2>
            <h2> { "Username: " } { store_c.username.clone() } </h2>
            <h2> { "Password: " } { store_c.password.clone() } </h2>
            <h2> { "Is authenticated: " } { store_c.is_authenticated } </h2>
            <span style="margin: 4px;"></span>
            <Link<Route> to={ Route::Home }>{ "Back to home" }</Link<Route>>
        </div>
    }
}

But I don't see anything in browser, the h2 for Username and Password stay empty.

I tried adding another field count to see if it adds up,

use serde::{Deserialize, Serialize};
use yewdux::store::Store;

#[derive(Default, Clone, PartialEq, Store, Serialize, Deserialize)]
#[store(storage = "local")] // or session
pub struct AuthStore {
    pub username: String,
    pub password: String,
    pub is_authenticated: bool,
    pub count: u32,
}
use crate::{
    components::forms::create_user_form::{CreateFormStateData, CreateUserForm},
    router::Route,
    stores::auth_store::AuthStore,
};
use course_byte_shared::{create_user, NewUser, User};
use gloo::console;
use yew::{function_component, html, use_state, Callback, Html};
use yew_router::prelude::{use_navigator, Link};
use yewdux::prelude::use_store;

#[function_component(CreateUser)]
pub fn create_user() -> Html {
    let new_user_data = use_state(User::default);

    let navigator = use_navigator().unwrap();

    let (store, dispatch) = use_store::<AuthStore>();
    let dp = dispatch.clone();
    let store_c = store.clone();

    let on_submit_form = Callback::from(move |data: CreateFormStateData| {
        let new_user_data_clone = new_user_data.clone();

        let navigator_clone = navigator.clone();

        let dispatch = dispatch.clone();
        let store = store.clone();

        wasm_bindgen_futures::spawn_local(async move {
            let navigator_clone = navigator_clone.clone();

            let dispatch = dispatch.clone();
            let store = store.clone();

            match create_user(NewUser {
                username: data.username.to_string(),
                email: data.email.to_string(),
                password: data.password.to_string(),
            })
            .await
            {
                Ok(user) => {
                    let username = user.username.clone();
                    let token = user.token.clone();
                    let token_c = user.token.clone();

                    new_user_data_clone.set(user);

                    dispatch.reduce_mut(move |state| {
                        state.username = username;
                        state.password = token;
                        state.is_authenticated = true;
                        state.count += 5;
                    });

                    console::log!("Token: ", token_c);
                }
                Err(error) => eprintln!("API Error: {:?}", error),
            };

            // console::log!("Sucessfully created new user, redirecting to home page..");
            // navigator_clone.push(&Route::Home);

            console::log!("Count after update: ", store.count);
        });
    });

    html! {
        <div>
            <h1> { "Create user" } </h1>
            <CreateUserForm on_submit={ on_submit_form }/>
            // <h2> { "Username: " } { dp.get().username.clone() } </h2>
            // <h2> { "Password: " } { dp.get().password.clone() } </h2>
            <h2> { "Username: " } { store_c.username.clone() } </h2>
            <h2> { "Password: " } { store_c.password.clone() } </h2>
            <h2> { "Count: " } { store_c.count } </h2>
            <h2> { "Is authenticated: " } { store_c.is_authenticated } </h2>
            <span style="margin: 4px;"></span>
            <Link<Route> to={ Route::Home }>{ "Back to home" }</Link<Route>>
        </div>
    }
}

But the count stays at 0.

Am I doing something wrong here?

apoorv569 commented 1 year ago

I got it working, the issue was that I was not splitting the Bearer part from the token.

            let split: Vec<&str> = auth_header.split_whitespace().collect();

            if split.len() == 2 && split[0] == "Bearer" {
                let auth_token = split[1];

                // Do stuff
            }

adding this fixed the problem.