UseReducer
UseReducer
is a hook that manages state using reducer function.
An alternative to UseState
.
Syntax
UseReducer<T>( T reducer(T state, RtAction action), T initialValue,);
UseReducer
accepts these arguments:
-
reducer
: A function that takes the currentstate
and anaction
, and returns a new state. initialState
: Initial value ofT
type that it will hold.
Properties & Methods
UseReducer
provides the following properties and methods:
value
: A getter that allows to read its state.-
dispatch
: A method that allows to dispatch an action to update the state.- Syntax:
1void dispatch(RtAction action);
- Syntax:
-
Methods inherited from
RtState
(Learn more here):-
update
: A method to notify changes after run a set of instructions. -
refresh
: A method to force to notify changes. - *
bind
: A method to bind an instance to it. - *
unbind
: A method to unbind an instance to it. - *
dispose
: A method to remove all listeners and free resources.
-
Usage
Declaration
UseReducer
can be initialized using the constructor class:
29 collapsed lines
1import 'package:reactter/reactter.dart';2
3class User {4 final String name;5 final int age;6
7 const User({required this.name, required this.age});8
9 @override10 String toString() => "User(name: $name, age: $age)";11}12
13class UserAction extends ReactterAction {14 UserAction.incrementedAge() : super(type: 'incremented_age', payload: null);15 UserAction.changedName(String name)16 : super(type: 'changed_name', payload: name);17}18
19User reducer(User state, ReactterAction action) {20 switch (action.type) {21 case "incremented_age":22 return User(state.name, state.age + 1);23 case "changed_name":24 return User(action.payload as String, state.age);25 default:26 return state;27 }28}29
30final uUser = UseReducer<User>(31 reducer,32 const User(33 name: "John Doe",34 age: 17,35 ),36);8 collapsed lines
37
38void main() {39 print("${uUser.value}") // User(name: "John Doe", age: 17)40 uUser.dispatch(UserAction.incrementedAge());41 print("${uUser.value}"); // User(name: "John Doe", age: 18)42 uUser.dispatch(UserAction.changedName("Jane Doe"));43 print("${uUser.value}"); // User(name: "Jane Done", age: 18)44}
Writting the action
The action is a class that inherits from the RtAction
class.
This class contains the action type
and payload
that will be dispatched to the reducer
method.
12 collapsed lines
1import 'package:reactter/reactter.dart';2
3class User {4 final String name;5 final int age;6
7 const User({required this.name, required this.age});8
9 @override10 String toString() => "User(name: $name, age: $age)";11}12
13class UserAction extends ReactterAction {14 UserAction.incrementedAge() : super(type: 'incremented_age', payload: null);15 UserAction.changedName(String name)16 : super(type: 'changed_name', payload: name);17}27 collapsed lines
18
19User reducer(User state, ReactterAction action) {20 switch (action.type) {21 case "incremented_age":22 return User(state.name, state.age + 1);23 case "changed_name":24 return User(action.payload as String, state.age);25 default:26 return state;27 }28}29
30final uUser = UseReducer<User>(31 reducer,32 const User(33 name: "John Doe",34 age: 17,35 ),36);37
38void main() {39 print("${uUser.value}") // User(name: "John Doe", age: 17)40 uUser.dispatch(UserAction.incrementedAge());41 print("${uUser.value}"); // User(name: "John Doe", age: 18)42 uUser.dispatch(UserAction.changedName("Jane Doe"));43 print("${uUser.value}"); // User(name: "Jane Done", age: 18)44}
Writting the reducer method
The reducer
method is a function that takes the current state
and an action
, and returns a new state.
This method is responsible for updating the state
based on the action
dispatched.
The state
is immutable, so it should return a new state
object.
18 collapsed lines
1import 'package:reactter/reactter.dart';2
3class User {4 final String name;5 final int age;6
7 const User({required this.name, required this.age});8
9 @override10 String toString() => "User(name: $name, age: $age)";11}12
13class UserAction extends ReactterAction {14 UserAction.incrementedAge() : super(type: 'incremented_age', payload: null);15 UserAction.changedName(String name)16 : super(type: 'changed_name', payload: name);17}18
19User reducer(User state, ReactterAction action) {20 switch (action.type) {21 case "incremented_age":22 return User(state.name, state.age + 1);23 case "changed_name":24 return User(action.payload as String, state.age);25 default:26 return state;27 }28}16 collapsed lines
29
30final uUser = UseReducer<User>(31 reducer,32 const User(33 name: "John Doe",34 age: 17,35 ),36);37
38void main() {39 print("${uUser.value}") // User(name: "John Doe", age: 17)40 uUser.dispatch(UserAction.incrementedAge());41 print("${uUser.value}"); // User(name: "John Doe", age: 18)42 uUser.dispatch(UserAction.changedName("Jane Doe"));43 print("${uUser.value}"); // User(name: "Jane Done", age: 18)44}
Dispatching an action and reading the state
The dispatch
method is responsible for dispatching an action to the reducer
method.
After dispatching an action, you can read the state using the value
property.
37 collapsed lines
1import 'package:reactter/reactter.dart';2
3class User {4 final String name;5 final int age;6
7 const User({required this.name, required this.age});8
9 @override10 String toString() => "User(name: $name, age: $age)";11}12
13class UserAction extends ReactterAction {14 UserAction.incrementedAge() : super(type: 'incremented_age', payload: null);15 UserAction.changedName(String name)16 : super(type: 'changed_name', payload: name);17}18
19User reducer(User state, ReactterAction action) {20 switch (action.type) {21 case "incremented_age":22 return User(state.name, state.age + 1);23 case "changed_name":24 return User(action.payload as String, state.age);25 default:26 return state;27 }28}29
30final uUser = UseReducer<User>(31 reducer,32 const User(33 name: "John Doe",34 age: 17,35 ),36);37
38void main() {39 print("${uUser.value}") // User(name: "John Doe", age: 17)40 uUser.dispatch(UserAction.incrementedAge());41 print("${uUser.value}"); // User(name: "John Doe", age: 18)42 uUser.dispatch(UserAction.changedName("Jane Doe"));43 print("${uUser.value}"); // User(name: "Jane Done", age: 18)44}
Using the action callable
The actions can be created as a callable class, extending from RtActionCallable
e.g.:
1class IncrementedEgeUserAction extends RtActionCallable<User, void> {2 const IncrementedEgeUserAction()3 : super(type: 'incremented_ege', payload: null);4
5 @override6 User call(User state) => User(name: state.name, age: state.age + 1);7}8
9class ChangedNameUserAction extends RtActionCallable<User, String> {10 final String name;11
12 const ChangedNameUserAction(this.name)13 : super(type: 'changed_name', payload: name);14
15 @override16 User call(User state) => User(name: payload, age: state.age);17}
RtActionCallable
has a call
method that returns the new state based on the state
and payload
.
The action callable can be applied in reducer method:
1User reducer(User state, RtAction action) {2 if (action is RtActionCallable) return action(state);3 return state;4}
And dispatched as:
1userState.dispatch(IncrementedEgeUserAction());2userState.dispatch(ChangedNameUserAction('Jane Doe'));
Updating the state
Use update
method to notify changes after run a set of instructions:
uState.update((value) { uState.value = "New value";});
Use refresh
method to force to notify changes.
userState.refresh();
Listening to changes
When value
has changed, the UseReducer
will emit the following events(learn about it here):
Lifecycle.willUpdate
event is triggered before thevalue
change orupdate
,refresh
methods have been invoked.Lifecycle.didUpdate
event is triggered after thevalue
change orupdate
,refresh
methods have been invoked.
Example of listening to changes:
1Rt.on(2 uUser,3 Lifecycle.didUpdate,4 (_, state) => print("State value has changed to: ${state.value}"),5);