Skip to content

Instantly share code, notes, and snippets.

@wayeast
Last active August 16, 2019 03:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wayeast/59b510f5163ca78273c413c34d9b2b12 to your computer and use it in GitHub Desktop.
Save wayeast/59b510f5163ca78273c413c34d9b2b12 to your computer and use it in GitHub Desktop.
Toy seed app to highlight puzzling issues
// Replace *lib.rs* in the seed-quickstart project with this file,
// then run `cargo make build && cargo make serve`.
#[macro_use]
extern crate seed;
#[macro_use]
extern crate serde;
use seed::prelude::*;
// Model
enum AuthModel {
Unknown,
Unauthenticated,
Authenticated(String),
}
enum StuffModel {
Disconnected,
Connected(String),
}
struct Model {
auth_model: AuthModel,
stuff_model: StuffModel,
}
impl Default for Model {
fn default() -> Self {
Self {
auth_model: AuthModel::Unknown,
stuff_model: StuffModel::Disconnected,
}
}
}
// Update
#[derive(Clone, Serialize, Deserialize, Debug)]
enum Msg {
WhoAmI,
Auth(AuthMsg),
Stuff(StuffMsg),
}
#[derive(Clone, Serialize, Deserialize, Debug)]
enum AuthMsg {
Login(Option<String>),
}
#[derive(Clone, Serialize, Deserialize, Debug)]
enum StuffMsg {
Connect(String),
}
fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
log!("update fn handling msg:", msg);
match msg {
Msg::Auth(msg) => {
update_auth(msg, &mut model.auth_model, &mut orders.proxy(Msg::Auth));
}
Msg::Stuff(msg) => {
update_stuff(msg, &mut model.stuff_model, &mut orders.proxy(Msg::Stuff));
}
Msg::WhoAmI => {
if let AuthModel::Authenticated(user) = &model.auth_model {
update_stuff(
StuffMsg::Connect(user.clone()),
&mut model.stuff_model,
&mut orders.proxy(Msg::Stuff),
);
}
}
}
}
fn update_auth(msg: AuthMsg, model: &mut AuthModel, _orders: &mut impl Orders<AuthMsg>) {
log!("update auth fn handling msg:", msg);
match msg {
AuthMsg::Login(res) => {
log!("updating login with res:", res);
match res {
Some(user) => *model = AuthModel::Authenticated(user),
None => *model = AuthModel::Unauthenticated,
}
}
}
}
/*
* 1) Here, I am using a pattern taken from the *server_integration* example (example_e)
* and which I use in *update_auth* above -- replacing *model with a new StuffModel value.
* Whereas following this same update in *update_auth* the dom is correctly rendered, here
* rendering does not appear to be triggered.
* **********************************************************************************/
fn update_stuff(msg: StuffMsg, model: &mut StuffModel, _orders: &mut impl Orders<StuffMsg>) {
log!("update stuff fn handling msg:", msg);
match msg {
StuffMsg::Connect(user) => *model = StuffModel::Connected(user), // this change is not rendered (?)!
}
}
// View
fn view(model: &Model) -> impl View<Msg> {
match &model.auth_model {
AuthModel::Unknown | AuthModel::Unauthenticated => {
view_auth(&model.auth_model).els().map_message(Msg::Auth)
}
AuthModel::Authenticated(_) => view_stuff(&model.stuff_model).els().map_message(Msg::Stuff),
}
}
fn view_auth(model: &AuthModel) -> impl View<AuthMsg> {
match model {
AuthModel::Unknown => div![
"auth state is unknown",
// check browser cookie cache
did_mount(|_| {
log!("did_mount sending Login(None)");
seed::update(Msg::Auth(AuthMsg::Login(None)));
}),
],
AuthModel::Unauthenticated => div![
// login form goes here
"log in as Alice",
button![
"I am Alice",
simple_ev(Ev::Click, AuthMsg::Login(Some("Alice".to_string()))),
],
],
AuthModel::Authenticated(_) => {
error!("Uh oh, authenticated model should never be handled by auth view fn");
div!["If you're seeing this, there is a big problem!!!"]
}
}
}
/*
* 2) Here, I am re-using a pattern from *view_auth* above -- when I find the model in an
* ambiguous state, I want to notify the app to perform some action and update state.
* Here, though, I have to add an additional inner div to the element -- if I use
* _exactly_ the same pattern as in *view_auth*, the *did_mount* closure will not fire!
* **********************************************************************************/
fn view_stuff(model: &StuffModel) -> impl View<StuffMsg> {
match model {
StuffModel::Disconnected => div![
// why does this extra div need to be here for did_mount to fire?
div![
"not yet connected",
did_mount(|_| {
log!("did_mount sendinng whoami msg");
seed::update(Msg::WhoAmI);
}),
],
],
StuffModel::Connected(user) => div![format!("Connected as {}", user),],
}
}
#[wasm_bindgen(start)]
pub fn render() {
seed::App::build(|_, _| Model::default(), update, view)
.window_events(|_| vec![trigger_update_handler()])
.finish()
.run();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment