yewstack / yew

Rust / Wasm framework for creating reliable and efficient web applications
https://yew.rs
Apache License 2.0
30.75k stars 1.43k forks source link

Try to seperate module but fail #275

Closed huangjj27 closed 4 years ago

huangjj27 commented 6 years ago

Description

I'm submitting a question

I'm trying to modularize the game of life example to learn about how to nest up component in yew. I separate the Cellule as a idependent component so that I could reuse the component in other form of game of life. So I impl it like:

#[derive(Clone, Copy, PartialEq)]
enum LifeState {
    Alive,
    Dead,
}

#[derive(Clone, Copy)]
pub struct Cellule {
    life_state: LifeState
}

pub enum Msg {
    Toggle,
    SetAlive,
    SetDead,
}

// methods in original example omitted
impl Cellule {
    pub fn toggle(&mut self) {
        match self.life_state {
            LifeState::Alive => self.life_state = LifeState::Dead,
            LifeState::Dead => self.life_state = LifeState::Alive,
        }
    }
}

impl<CTX> Component<CTX> for Cellule { ... }

impl<CTX, COMP> Renderable<CTX, COMP> for Cellule 
where
    CTX: 'static, COMP: Component<CTX>,
{
    fn view(&self) -> Html<CTX, COMP> {
        html! {
           <div class=("game-cellule", if self.life_state == LifeState::Alive { "cellule-live" } else { "cellule-dead" }),
            onclick=|_| Msg::Toggle,> </div> 
        }
    }
}

and In the GameOfLife model, I call the the view method like:

impl<CTX> Renderable<CTX, GameOfLife> for GameOfLife
where
    CTX: AsMut<IntervalService> + 'static,
{
    fn view(&self) -> Html<CTX, Self> {
        html! {
            <div>
                <section class="game-container",>
                    <header class="app-header",>
                        <img src="favicon.ico", class="app-logo",/>
                        <h1 class="app-title",>{ "Game of Life" }</h1>
                    </header>
                    <section class="game-area",>
                        <div class="game-of-life",>
                            { for self.cellules.iter().map(|cell| cell.view()) }  <!-- change the mapping -->
                        </div>
                        <div class="game-buttons",>
                            <button class="game-button", onclick=|_| Msg::Random,>{ "Random" }</button>
                            <button class="game-button", onclick=|_| Msg::Step,>{ "Step" }</button>
                            <button class="game-button", onclick=|_| Msg::Start,>{ "Start" }</button>
                            <button class="game-button", onclick=|_| Msg::Stop,>{ "Stop" }</button>
                            <button class="game-button", onclick=|_| Msg::Reset,>{ "Reset" }</button>
                        </div>
                    </section>
                </section>
                <footer class="app-footer",>
                    <strong class="footer-text",>
                      { "Game of Life - a yew experiment " }
                    </strong>
                    <a href="https://github.com/DenisKolodin/yew", target="_blank",>{ "source" }</a>
                </footer>
            </div>
        }
    }
}

Expected Results

I think this would decouple the Cellule and GameOfLife, but I failed.

Actual Results

It reminds me that I have to use the Message of COMP type, which means I can't decouple the Cellule with GameOfLife as an independent component

error[E0271]: type mismatch resolving `<COMP as yew::html::Component<CTX>>::Mess                            age == cellule::Msg`
  --> src\cellule.rs:83:9
   |
83 | /         html! {
84 | |            <div class=("game-cellule", if self.life_state == LifeState::A                            live { "cellule-live" } else { "cellule-dead" }),
85 | |             onclick=|_| Msg::Toggle,> </div>
86 | |         }
   | |_________^ expected associated type, found enum `cellule::Msg`
   |
   = note: expected type `<COMP as yew::html::Component<CTX>>::Message`
              found type `cellule::Msg`
   = note: required because of the requirements on the impl of `yew::virtual_dom                            ::Listener<CTX, COMP>` for `yew::html::onclick::Wrapper<[closure@<html_impl macr                            os>:50:15: 50:19]>`
   = note: required for the cast to the object type `yew::virtual_dom::Listener<                            CTX, COMP>`
   = note: this error originates in a macro outside of the current crate (in Nig                            htly builds, run with -Z external-macro-backtrace for more info)

Context (Environment)

jstarry commented 4 years ago

@huangjj27 would you like to give it another shot now that https://github.com/yewstack/yew/pull/783 removes the COMP type restriction?