From 5c2c9cb58a7a5d863a885be263ca92128d9397c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Le=C3=B3n?= Date: Mon, 20 May 2024 01:56:29 -0600 Subject: [PATCH] doc: Add `UseReducer` documentation. --- .../src/content/docs/hooks/use_reducer.mdx | 145 ++++++++++++++++++ .../examples/use_reducer_example.dart.code | 44 ++++++ 2 files changed, 189 insertions(+) create mode 100644 website/src/content/docs/hooks/use_reducer.mdx create mode 100644 website/src/examples/use_reducer_example.dart.code diff --git a/website/src/content/docs/hooks/use_reducer.mdx b/website/src/content/docs/hooks/use_reducer.mdx new file mode 100644 index 00000000..5aec02d5 --- /dev/null +++ b/website/src/content/docs/hooks/use_reducer.mdx @@ -0,0 +1,145 @@ +--- +title: UseReducer +description: The useReducer hook is a more advanced way to manage state in Reactter. +--- +import { HM, HT } from '@/components/Highlight'; +import { Code } from "@astrojs/starlight/components"; +import MDXRedry from '@/components/MDXRedry.astro'; +import StateMethodsLite from '@/content/docs/shareds/state_methods_lite.mdx'; +import UseReducerExample from '@/examples/use_reducer_example.dart.code?raw'; +import * as NoteStateValueNotifies from '@/content/docs/shareds/note_state_value_notifies.mdx'; +import * as ListeningChangesHook from '@/content/docs/shareds/listening_changes_hook.mdx'; + +export const mark = ["UserAction", "UseReducer", "ReactterAction", /([^u]User)/g, "reducer", ".dispatch", ".value"]; + +`UseReducer` is a [hook](/reactter/core_concepts/hooks) that manages state using reducer method. +An alternative to [`UseState`](/reactter/hooks/use_state). + +:::tip +`UseReducer` is usually preferable over `UseState` when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. +::: + +## Syntax + +```dart showLineNumbers=false +UseReducer( + T reducer(T state, ReactterAction action), + T initialValue, +); +``` + +`UseReducer` accepts two properties: + +- `reducer`: A function that takes the current `state` and an `action`, and returns a new state. +- `initialState`: Initial value of `T` 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: + ```dart + void dispatch(ReactterAction action); + ``` + + +## Usage + +### Declaration + +`UseReducer` can be initialized using the constructor class: + + + +### Writting the action + +The action is a class that inherits from the `ReactterAction` class. + +This class contains the action `type` and `payload` that will be dispatched to the `reducer` method. + + + +### 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. + + + +### 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. + + + + + +### Using the action callable + +The actions can be created as a callable class, extending from `ReactterActionCallable` e.g.: + +```dart "ReactterActionCallable" "call" "type" "payload" +class IncrementedEgeUserAction extends ReactterActionCallable { + const IncrementedEgeUserAction() + : super(type: 'incremented_ege', payload: null); + + @override + User call(User state) => User(name: state.name, age: state.age + 1); +} + +class ChangedNameUserAction extends ReactterActionCallable { + final String name; + + const ChangedNameUserAction(this.name) + : super(type: 'changed_name', payload: name); + + @override + User call(User state) => User(name: payload, age: state.age); +} +``` + +`ReactterActionCallable` has a `call` method that returns the new state based on the `state` and `payload`. + +The action callable can be applied in reducer method: + +```dart "ReactterActionCallable" +User reducer(User state, ReactterAction action) { + if (action is ReactterActionCallable) return action(state); + return state; +} +``` +And dispatched as: + +```dart ".dispatch" +userState.dispatch(IncrementedEgeUserAction()); +userState.dispatch(ChangedNameUserAction('Jane Doe')); +``` + +### Updating the state + +Use `update` method to notify changes after run a set of instructions: + +```dart showLineNumbers=false ".update" +uState.update((value) { + uState.value = "New value"; +}); +``` + +Use `refresh` method to force to notify changes. + +```dart showLineNumbers=false ".refresh" +userState.refresh(); +``` + +### Listening to changes + + \ No newline at end of file diff --git a/website/src/examples/use_reducer_example.dart.code b/website/src/examples/use_reducer_example.dart.code new file mode 100644 index 00000000..b0eb304d --- /dev/null +++ b/website/src/examples/use_reducer_example.dart.code @@ -0,0 +1,44 @@ +import 'package:reactter/reactter.dart'; + +class User { + final String name; + final int age; + + const User({required this.name, required this.age}); + + @override + String toString() => "User(name: $name, age: $age)"; +} + +class UserAction extends ReactterAction { + UserAction.incrementedAge() : super(type: 'incremented_age', payload: null); + UserAction.changedName(String name) + : super(type: 'changed_name', payload: name); +} + +User reducer(User state, ReactterAction action) { + switch (action.type) { + case "incremented_age": + return User(state.name, state.age + 1); + case "changed_name": + return User(action.payload as String, state.age); + default: + return state; + } +} + +final uUser = UseReducer( + reducer, + const User( + name: "John Doe", + age: 17, + ), +); + +void main() { + print("${uUser.value}") // User(name: "John Doe", age: 17) + uUser.dispatch(UserAction.incrementedAge()); + print("${uUser.value}"); // User(name: "John Doe", age: 18) + uUser.dispatch(UserAction.changedName("Jane Doe")); + print("${uUser.value}"); // User(name: "Jane Done", age: 18) +}