Skip to content

Commit 706fb48

Browse files
futursolosiku2
andauthored
Reliable use_reducer dispatch and use_state setter (#2126)
* Add Redirect Comp. * Fix router behaviour. * Fix output. * Fix pr-flow. * Remove Redirect. * Readd 77b46bf. * Reliable dispatch for use_reducer. * Detachable Dispatcher and Setter. * Update docs wording. * Update website/docs/concepts/function-components/pre-defined-hooks.md Co-authored-by: Simon <[email protected]> * Update website/docs/concepts/function-components/pre-defined-hooks.md Co-authored-by: Simon <[email protected]> * Update website/docs/concepts/function-components/pre-defined-hooks.md Co-authored-by: Simon <[email protected]> Co-authored-by: Simon <[email protected]>
1 parent f43760e commit 706fb48

File tree

7 files changed

+667
-386
lines changed

7 files changed

+667
-386
lines changed

examples/function_todomvc/src/main.rs

Lines changed: 5 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use gloo::storage::{LocalStorage, Storage};
2-
use state::{Entry, Filter, State};
3-
use std::rc::Rc;
2+
use state::{Action, Filter, State};
43
use strum::IntoEnumIterator;
54
use yew::{classes, function_component, html, use_effect_with_deps, use_reducer, Callback};
65

@@ -13,100 +12,14 @@ use components::{
1312
info_footer::InfoFooter,
1413
};
1514

16-
pub enum Action {
17-
Add(String),
18-
Edit((usize, String)),
19-
Remove(usize),
20-
SetFilter(Filter),
21-
ToggleAll,
22-
Toggle(usize),
23-
ClearCompleted,
24-
}
25-
2615
const KEY: &str = "yew.functiontodomvc.self";
2716

2817
#[function_component(App)]
2918
fn app() -> Html {
30-
let state = use_reducer(
31-
|prev: Rc<State>, action: Action| match action {
32-
Action::Add(description) => {
33-
let mut entries = prev.entries.clone();
34-
entries.push(Entry {
35-
id: entries.last().map(|entry| entry.id + 1).unwrap_or(1),
36-
description,
37-
completed: false,
38-
});
39-
State {
40-
entries,
41-
filter: prev.filter,
42-
}
43-
}
44-
Action::Remove(id) => {
45-
let mut entries = prev.entries.clone();
46-
entries.retain(|entry| entry.id != id);
47-
State {
48-
entries,
49-
filter: prev.filter,
50-
}
51-
}
52-
Action::Toggle(id) => {
53-
let mut entries = prev.entries.clone();
54-
let entry = entries.iter_mut().find(|entry| entry.id == id);
55-
if let Some(entry) = entry {
56-
entry.completed = !entry.completed;
57-
}
58-
State {
59-
entries,
60-
filter: prev.filter,
61-
}
62-
}
63-
Action::Edit((id, description)) => {
64-
let mut entries = prev.entries.clone();
65-
66-
if description.is_empty() {
67-
entries.retain(|entry| entry.id != id)
68-
}
69-
70-
let entry = entries.iter_mut().find(|entry| entry.id == id);
71-
if let Some(entry) = entry {
72-
entry.description = description;
73-
}
74-
State {
75-
entries,
76-
filter: prev.filter,
77-
}
78-
}
79-
Action::ToggleAll => {
80-
let mut entries = prev.entries.clone();
81-
for entry in &mut entries {
82-
if prev.filter.fits(entry) {
83-
entry.completed = !entry.completed;
84-
}
85-
}
86-
State {
87-
entries,
88-
filter: prev.filter,
89-
}
90-
}
91-
Action::ClearCompleted => {
92-
let mut entries = prev.entries.clone();
93-
entries.retain(|e| Filter::Active.fits(e));
94-
State {
95-
entries,
96-
filter: prev.filter,
97-
}
98-
}
99-
Action::SetFilter(filter) => State {
100-
filter,
101-
entries: prev.entries.clone(),
102-
},
103-
},
104-
// Initial state
105-
State {
106-
entries: LocalStorage::get(KEY).unwrap_or_else(|_| vec![]),
107-
filter: Filter::All, // TODO: get from uri
108-
},
109-
);
19+
let state = use_reducer(|| State {
20+
entries: LocalStorage::get(KEY).unwrap_or_else(|_| vec![]),
21+
filter: Filter::All, // TODO: get from uri
22+
});
11023

11124
// Effect
11225
use_effect_with_deps(

examples/function_todomvc/src/state.rs

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
use std::rc::Rc;
2+
use yew::prelude::*;
3+
14
use serde::{Deserialize, Serialize};
25
use strum_macros::{EnumIter, ToString};
36

4-
#[derive(Clone, Debug, Serialize, Deserialize)]
7+
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
58
pub struct State {
69
pub entries: Vec<Entry>,
710
pub filter: Filter,
@@ -38,3 +41,100 @@ impl Filter {
3841
}
3942
}
4043
}
44+
45+
pub enum Action {
46+
Add(String),
47+
Edit((usize, String)),
48+
Remove(usize),
49+
SetFilter(Filter),
50+
ToggleAll,
51+
Toggle(usize),
52+
ClearCompleted,
53+
}
54+
55+
impl Reducible for State {
56+
type Action = Action;
57+
58+
fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
59+
match action {
60+
Action::Add(description) => {
61+
let mut entries = self.entries.clone();
62+
entries.push(Entry {
63+
id: entries.last().map(|entry| entry.id + 1).unwrap_or(1),
64+
description,
65+
completed: false,
66+
});
67+
State {
68+
entries,
69+
filter: self.filter,
70+
}
71+
.into()
72+
}
73+
Action::Remove(id) => {
74+
let mut entries = self.entries.clone();
75+
entries.retain(|entry| entry.id != id);
76+
State {
77+
entries,
78+
filter: self.filter,
79+
}
80+
.into()
81+
}
82+
Action::Toggle(id) => {
83+
let mut entries = self.entries.clone();
84+
let entry = entries.iter_mut().find(|entry| entry.id == id);
85+
if let Some(entry) = entry {
86+
entry.completed = !entry.completed;
87+
}
88+
State {
89+
entries,
90+
filter: self.filter,
91+
}
92+
.into()
93+
}
94+
Action::Edit((id, description)) => {
95+
let mut entries = self.entries.clone();
96+
97+
if description.is_empty() {
98+
entries.retain(|entry| entry.id != id)
99+
}
100+
101+
let entry = entries.iter_mut().find(|entry| entry.id == id);
102+
if let Some(entry) = entry {
103+
entry.description = description;
104+
}
105+
State {
106+
entries,
107+
filter: self.filter,
108+
}
109+
.into()
110+
}
111+
Action::ToggleAll => {
112+
let mut entries = self.entries.clone();
113+
for entry in &mut entries {
114+
if self.filter.fits(entry) {
115+
entry.completed = !entry.completed;
116+
}
117+
}
118+
State {
119+
entries,
120+
filter: self.filter,
121+
}
122+
.into()
123+
}
124+
Action::ClearCompleted => {
125+
let mut entries = self.entries.clone();
126+
entries.retain(|e| Filter::Active.fits(e));
127+
State {
128+
entries,
129+
filter: self.filter,
130+
}
131+
.into()
132+
}
133+
Action::SetFilter(filter) => State {
134+
filter,
135+
entries: self.entries.clone(),
136+
}
137+
.into(),
138+
}
139+
}
140+
}

0 commit comments

Comments
 (0)