Skip to content

Commit

Permalink
doc: Add UseReducer documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
CarLeonDev committed May 20, 2024
1 parent 8e8dcea commit 5c2c9cb
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 0 deletions.
145 changes: 145 additions & 0 deletions website/src/content/docs/hooks/use_reducer.mdx
Original file line number Diff line number Diff line change
@@ -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"];

<HT><a href="https://pub.dev/documentation/reactter/latest/reactter/UseReducer-class.html" target="_blank">`UseReducer`</a></HT> is a [hook](/reactter/core_concepts/hooks) that manages state using reducer method.
An alternative to <HT>[`UseState`](/reactter/hooks/use_state)</HT>.

:::tip
<HT>`UseReducer`</HT> is usually preferable over <HT>`UseState`</HT> 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>(
T reducer(T state, ReactterAction action),
T initialValue,
);
```

<HT>`UseReducer`</HT> accepts two properties:

- <HM>`reducer`</HM>: A function that takes the current `state` and an `action`, and returns a new state.
- `initialState`: Initial value of <HT>`T`</HT> type that it will hold.

## Properties & Methods

<HT>`UseReducer`</HT> provides the following properties and methods:

- `value`: A getter that allows to read its state.
- <HM>`dispatch`</HM>: A method that allows to dispatch an action to update the state.
- Syntax:
```dart
void dispatch(ReactterAction action);
```
<StateMethodsLite />

## Usage

### Declaration

<HT>`UseReducer`</HT> can be initialized using the constructor class:

<Code code={UseReducerExample} lang="dart" mark={mark} collapse={["1-29", "37-100"]} />

### Writting the action

The action is a class that inherits from the <HT>`ReactterAction`</HT> class.

This class contains the action `type` and `payload` that will be dispatched to the <HM>`reducer`</HM> method.

<Code code={UseReducerExample} lang="dart" mark={mark} collapse={["1-12", "18-100"]} />

### Writting the reducer method

The <HM>`reducer`</HM> 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.

<Code code={UseReducerExample} lang="dart" mark={mark} collapse={["1-18", "29-100"]} />

### Dispatching an action and reading the state

The <HM>`dispatch`</HM> method is responsible for dispatching an action to the <HM>`reducer`</HM> method.
After dispatching an action, you can read the state using the `value` property.

<Code code={UseReducerExample} lang="dart" mark={mark} collapse={["1-37"]} />

<MDXRedry mdx={NoteStateValueNotifies} vars={{
stateName: 'UseReducer',
}}/>

### Using the action callable

The actions can be created as a callable class, extending from <HT>`ReactterActionCallable`</HT> e.g.:

```dart "ReactterActionCallable" "call" "type" "payload"
class IncrementedEgeUserAction extends ReactterActionCallable<User, void> {
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<User, String> {
final String name;
const ChangedNameUserAction(this.name)
: super(type: 'changed_name', payload: name);
@override
User call(User state) => User(name: payload, age: state.age);
}
```

<HT>`ReactterActionCallable`</HT> has a <HM>`call`</HM> 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 <HM>`update`</HM> method to notify changes after run a set of instructions:

```dart showLineNumbers=false ".update"
uState.update((value) {
uState.value = "New value";
});
```

Use <HM>`refresh`</HM> method to force to notify changes.

```dart showLineNumbers=false ".refresh"
userState.refresh();
```

### Listening to changes

<MDXRedry mdx={ListeningChangesHook} vars={{
stateName: 'UseReducer',
stateVariable: 'uUser',
}}/>
44 changes: 44 additions & 0 deletions website/src/examples/use_reducer_example.dart.code
Original file line number Diff line number Diff line change
@@ -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<User>(
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)
}

0 comments on commit 5c2c9cb

Please sign in to comment.