Get rid of unnecessary create_effect calls

This commit is contained in:
Jeremy Wall 2022-12-29 12:42:05 -06:00
parent 47fab33561
commit a39ed5589f
9 changed files with 58 additions and 99 deletions

View File

@ -185,6 +185,7 @@ impl MessageMapper<Message, AppState> for StateMachine {
#[instrument(skip_all, fields(?msg))]
fn map<'ctx>(&self, cx: Scope<'ctx>, msg: Message, original: &'ctx Signal<AppState>) {
let mut original_copy = original.get().as_ref().clone();
debug!("handling state message");
match msg {
Message::ResetRecipeCounts => {
let mut map = BTreeMap::new();

View File

@ -48,6 +48,7 @@ pub fn AddRecipe<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View
)
});
// TODO(jwall): This create effect should no longer be necessary;
create_effect(cx, move || {
create_recipe_signal.track();
if !*dirty.get_untracked() {

View File

@ -43,7 +43,6 @@ fn check_category_text_parses(unparsed: &str, error_text: &Signal<String>) -> bo
#[instrument(skip_all)]
#[component]
pub fn Categories<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View<G> {
let save_signal = create_signal(cx, ());
let error_text = create_signal(cx, String::new());
let category_text: &Signal<String> = create_signal(cx, String::new());
let dirty = create_signal(cx, false);
@ -61,21 +60,6 @@ pub fn Categories<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> Vie
}
});
create_effect(cx, move || {
save_signal.track();
if !*dirty.get() {
return;
}
spawn_local_scoped(cx, {
async move {
sh.dispatch(
cx,
Message::SetCategoryMap(category_text.get_untracked().as_ref().clone()),
);
}
});
});
let dialog_view = view! {cx,
dialog(id="error-dialog") {
article{
@ -102,10 +86,15 @@ pub fn Categories<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> Vie
check_category_text_parses(category_text.get().as_str(), error_text);
}) { "Check" } " "
span(role="button", on:click=move |_| {
// TODO(jwall): check and then save the categories.
if !*dirty.get() {
return;
}
if check_category_text_parses(category_text.get().as_str(), error_text) {
debug!("triggering category save");
save_signal.trigger_subscribers();
sh.dispatch(
cx,
Message::SetCategoryMap(category_text.get_untracked().as_ref().clone()),
);
}
}) { "Save" }
}

View File

@ -67,44 +67,8 @@ pub fn Editor<'ctx, G: Html>(cx: Scope<'ctx>, props: RecipeComponentProps<'ctx>)
});
let id = create_memo(cx, || recipe.get().recipe_id().to_owned());
let save_signal = create_signal(cx, ());
let dirty = create_signal(cx, false);
debug!("Creating effect");
create_effect(cx, move || {
save_signal.track();
if !*dirty.get_untracked() {
debug!("Recipe text is unchanged");
return;
}
debug!("Recipe text is changed");
spawn_local_scoped(cx, {
let store = crate::api::HttpStore::get_from_context(cx);
async move {
debug!("Attempting to save recipe");
if let Err(e) = store
.save_recipes(vec![RecipeEntry(
id.get_untracked().as_ref().clone(),
text.get_untracked().as_ref().clone(),
)])
.await
{
error!(?e, "Failed to save recipe");
error_text.set(format!("{:?}", e));
} else {
// We also need to set recipe in our state
dirty.set(false);
if let Ok(recipe) = recipes::parse::as_recipe(text.get_untracked().as_ref()) {
sh.dispatch(
cx,
Message::SetRecipe(id.get_untracked().as_ref().to_owned(), recipe),
);
}
};
}
});
});
debug!("creating editor view");
view! {cx,
div(class="grid") {
@ -121,7 +85,36 @@ pub fn Editor<'ctx, G: Html>(cx: Scope<'ctx>, props: RecipeComponentProps<'ctx>)
let unparsed = text.get();
if check_recipe_parses(unparsed.as_str(), error_text, aria_hint) {
debug!("triggering a save");
save_signal.trigger_subscribers();
if !*dirty.get_untracked() {
debug!("Recipe text is unchanged");
return;
}
debug!("Recipe text is changed");
spawn_local_scoped(cx, {
let store = crate::api::HttpStore::get_from_context(cx);
async move {
debug!("Attempting to save recipe");
if let Err(e) = store
.save_recipes(vec![RecipeEntry(
id.get_untracked().as_ref().clone(),
text.get_untracked().as_ref().clone(),
)])
.await
{
error!(?e, "Failed to save recipe");
error_text.set(format!("{:?}", e));
} else {
// We also need to set recipe in our state
dirty.set(false);
if let Ok(recipe) = recipes::parse::as_recipe(text.get_untracked().as_ref()) {
sh.dispatch(
cx,
Message::SetRecipe(id.get_untracked().as_ref().to_owned(), recipe),
);
}
};
}
});
} else {
}
}) { "Save" }

View File

@ -35,17 +35,6 @@ pub fn RecipePlan<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> Vie
}
rows
});
let refresh_click = create_signal(cx, false);
let save_click = create_signal(cx, false);
// FIXME(jwall): We should probably make this a dispatch method instead.
create_effect(cx, move || {
refresh_click.track();
sh.dispatch(cx, Message::LoadState);
});
create_effect(cx, move || {
save_click.track();
sh.dispatch(cx, Message::SaveState);
});
view! {cx,
table(class="recipe_selector no-print") {
(View::new_fragment(
@ -66,17 +55,14 @@ pub fn RecipePlan<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> Vie
))
}
input(type="button", value="Reset", on:click=move |_| {
// Poor man's click event signaling.
let toggle = !*refresh_click.get();
refresh_click.set(toggle);
sh.dispatch(cx, Message::LoadState);
})
input(type="button", value="Clear All", on:click=move |_| {
sh.dispatch(cx, Message::ResetRecipeCounts);
})
input(type="button", value="Save Plan", on:click=move |_| {
// Poor man's click event signaling.
let toggle = !*save_click.get();
save_click.set(toggle);
sh.dispatch(cx, Message::SaveState);
})
}
}

View File

@ -53,7 +53,7 @@ pub fn RecipeSelection<'ctx, G: Html>(
view! {cx,
div() {
label(for=for_id) { a(href=href) { (*title) } }
input(type="number", class="item-count-sel", min="0", value=count, name=name, on:change=move |_| {
input(type="number", class="item-count-sel", min="0", bind:value=count, name=name, on:change=move |_| {
debug!(idx=%id, count=%(*count.get()), "setting recipe count");
sh.dispatch(cx, Message::UpdateRecipeCount(id.as_ref().clone(), count.get().parse().expect("Count is not a valid usize")));
})

View File

@ -192,12 +192,6 @@ fn make_shopping_table<'ctx, G: Html>(
#[component]
pub fn ShoppingList<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View<G> {
let show_staples = create_signal(cx, true);
let save_click = create_signal(cx, ());
create_effect(cx, move || {
save_click.track();
info!("Registering save request for inventory");
sh.dispatch(cx, Message::SaveState);
});
view! {cx,
h1 { "Shopping List " }
label(for="show_staples_cb") { "Show staples" }
@ -209,8 +203,9 @@ pub fn ShoppingList<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> V
input(type="button", value="Reset", class="no-print", on:click=move |_| {
sh.dispatch(cx, Message::ResetInventory);
})
input(type="button", value="Save", class="no-print", on:click=|_| {
save_click.trigger_subscribers();
input(type="button", value="Save", class="no-print", on:click=move |_| {
info!("Registering save request for inventory");
sh.dispatch(cx, Message::SaveState);
})
}
}

View File

@ -11,7 +11,8 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use sycamore::{futures::spawn_local_scoped, prelude::*};
use sycamore::futures::spawn_local_scoped;
use sycamore::prelude::*;
use tracing::{debug, info};
use crate::app_state::{Message, StateHandler};
@ -20,20 +21,6 @@ use crate::app_state::{Message, StateHandler};
pub fn LoginForm<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View<G> {
let username = create_signal(cx, "".to_owned());
let password = create_signal(cx, "".to_owned());
let clicked = create_signal(cx, ("".to_owned(), "".to_owned()));
create_effect(cx, move || {
let (username, password) = (*clicked.get()).clone();
if username != "" && password != "" {
spawn_local_scoped(cx, async move {
let store = crate::api::HttpStore::get_from_context(cx);
debug!("authenticating against ui");
// TODO(jwall): Navigate to plan if the below is successful.
if let Some(user_data) = store.authenticate(username, password).await {
sh.dispatch(cx, Message::SetUserData(user_data));
}
});
}
});
view! {cx,
form() {
label(for="username") { "Username" }
@ -42,9 +29,18 @@ pub fn LoginForm<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View
input(type="password", bind:value=password)
input(type="button", value="Login", on:click=move |_| {
info!("Attempting login request");
clicked.set(((*username.get_untracked()).clone(), (*password.get_untracked()).clone()));
let (username, password) = ((*username.get_untracked()).clone(), (*password.get_untracked()).clone());
if username != "" && password != "" {
spawn_local_scoped(cx, async move {
let store = crate::api::HttpStore::get_from_context(cx);
debug!("authenticating against ui");
// TODO(jwall): Navigate to plan if the below is successful.
if let Some(user_data) = store.authenticate(username, password).await {
sh.dispatch(cx, Message::SetUserData(user_data));
}
});
}
debug!("triggering login click subscribers");
clicked.trigger_subscribers();
}) { }
}
}

View File

@ -28,8 +28,6 @@ pub fn UI<G: Html>(cx: Scope) -> View<G> {
let app_state = crate::app_state::AppState::new();
let sh = crate::app_state::get_state_handler(cx, app_state, store);
let view = create_signal(cx, View::empty());
// FIXME(jwall): We need a way to trigger refreshes when required. Turn this
// into a create_effect with a refresh signal stored as a context.
spawn_local_scoped(cx, {
async move {
sh.dispatch(cx, Message::LoadState);