1

I'm using Yew to program a theme switcher that by clicking cycles through different themes. This is my update function. It gets the current theme which is stored in shared state, depending on what would come next inside theme_cycle the theme value inside the shared state gets set to it.

fn update(&mut self, msg: Self::Message) -> ShouldRender {
    match msg {
        Msg::ChangeTheme => {
            let theme_cycle: [&str; 3] = ["light", "dark", "rust"];
            let current_theme = self.props.handle.state().theme.clone();
            // eval next theme
            let next_theme = match theme_cycle.iter().position(|x| x == &current_theme) {
                None => theme_cycle[0].to_string(),
                Some(i) => {
                    if i >= (current_theme.len() - 1) {
                        theme_cycle[0].to_string()
                    } else {
                        theme_cycle[i + 1].to_string()
                    }
                },
            };
            // set next theme
            self.props.handle.reduce(move |state| state.theme = next_theme.clone());
            // store it inside localstorage
        },
        Msg::ToggleLangDropdown => self.show_dropdown = !self.show_dropdown,
    };
    true
}

But if the theme val inside shared state is "rust" and I click the button again that calls Msg::ChangeTheme, the theme should be set to "light" but instead my code panics and I get an "Uncaught Error: undefined" inside the Browser Console.

wjatscheslaw
  • 49
  • 1
  • 10

1 Answers1

0

I've found a workaround; instead of using an array and accessing the values, I've tried to do the same task but just with iterators and made sure that the update function takes no ownership of any variable outside the function itself (I don't really know if that is really necessary though...)

fn update(&mut self, msg: Self::Message) -> ShouldRender {
    match msg {
        Msg::ChangeTheme => {
            let theme_cycle = ["light".to_string(), "dark".to_string(), "rust".to_string()];
            let current_theme = self.props.handle.state().theme.clone();
            let indexof_current_theme = match theme_cycle.iter().position(|x| x.to_string() == current_theme) {
                None => 0,
                Some(x) => x.clone(),
            };
            let next_theme = match theme_cycle.iter().nth(indexof_current_theme + 1) {
                None => theme_cycle.iter().nth(0).unwrap().clone(),
                Some(x) => x.clone(),
            };
            self.props.handle.reduce(move |state| state.theme = next_theme.to_string());
        },
        Msg::ToggleLangDropdown => self.show_lang_dropdown = !self.show_lang_dropdown,
        Msg::ToggleThemeDropdown => self.show_theme_dropdown = !self.show_theme_dropdown,
    };
    true
}

Still would be cool if anyone knows what I did wrong in my first attempt.

wjatscheslaw
  • 49
  • 1
  • 10