---
title: Side Effects
description: Learn the basics behind side effects in ReArch.
---

# Side Effects
Although side effects may seem confusing at first, they are the reason ReArch is so unique.
Whenever some feature is not available in the core ReArch implementation,
chances are you just need to create a side effect to add it!

Side effects in the Dart/Flutter implementation are heavily inspired by React hooks,
but share some key differences.
In the Rust implementation, side effects are largely a new paradigm, and may take some adjustment.


## The Theory
<Info>
  This section delves a bit deeper into theory than other parts of the documentation;
  feel free to skip it and go straight to the examples if you wish.
</Info>

In ReArch, side effects are modeled as:
- Some private mutable data (only accessible to the side effect itself)
- A way to mutate that private data *outside* of the build (which in turn triggers rebuilds)

Then, side effects expose an api that wrap around their private data and any external mutation(s).

For a concrete example, let's examine the state side effect.
The state side effect's api is the current state and a function that sets that current state.
Internally, the private mutable data is just the current state itself,
and the rebuilding mutation exposed is just a function that
sets the private data (the current state) to a given new state.

Although it may not seem like it,
you can model *any* side effect using this same exact methodology.

Further, while capsules form a data flow/dependency graph, side effects form a *tree*.
This enables side effects to have their own private side effect(s), enabling easy composition.


## An Example
<Error>
  In Dart, do not conditionally call `use.fooBar()`!
  In Rust, do not conditionally call `register(effect())`!
  Doing so is considered an error;
  *never* wrap `use.fooBar()`/`register(effect())` in an `if` statement.
  ReArch will likely throw a fit as soon as you mess this up, but it can't catch 100% of cases.
</Error>

Here is a quick example showing how to use a few side effects.
See the side effect library and api documentation for more information.

<CodeGroup title="Using side effects">
  ```dart
  // A toy capsule that uses a few side effects
  (Something, void Function(int)) usesSideEffects(CapsuleHandle use) {
    // First, let's create some mutable state
    final (state, setState) = use.state(1234);

    // Next, let's create an instance of some object using this state
    final somethingMadeWithState = use.memo(() => Something(state), [state]);

    // Finally, let's register this object to be disposed whenever a new one is created
    use.effect(() => somethingMadeWithState.dispose, [somethingMadeWithState]);

	// ...and let's return that object along with a way to set the state
    return (somethingMadeWithState, setState);
  };
  ```

  ```rust
  // Capsule that counts the number of times it builds
  fn count_builds(CapsuleHandle { mut get, register }: CapsuleHandle) -> u64 {
      let is_first_build = register(effects::is_first_build());
      if is_first_build {
          1
      } else {
          get(count_builds) + 1
      }
  }

  // Alternative way to write a capsule that counts the number of times it builds
  fn alt_count_builds(CapsuleHandle { register, .. }: CapsuleHandle) -> u64 {
      let builds = register(effects::value::<MutRef<_>>(0));
      *builds += 1;
      *builds
  }
  ```
</CodeGroup>


## Widget Side Effects (Flutter Only)
In Flutter, in addition to the capsule-only `SideEffect`,
there is also a `WidgetSideEffect`.
`WidgetSideEffect`s pack in some widget-specific functionality,
like listening to widget lifecycle events and exposing a `BuildContext`.

When possible, try to write side effects as regular `SideEffect`s
(to enable reusability amongst capsules and widgets),
although it is appropriate to make `WidgetSideEffect`s:
- When you need some widget-specific functionality
- When it only would ever make sense to use the side effect from a widget
(say, for an `AnimationController`).

See [the builtin `WidgetSideEffect`s](https://pub.dev/documentation/flutter_rearch/latest/flutter_rearch/BuiltinWidgetSideEffects.html).


## Transactions
Multiple side effects can be updated in one batch rebuild via _side effect transactions_.
This can be helpful when you wish to update _unrelated_ data that needs to be updated together.
Often, _this is not needed_. However, it can be helpful in some select situations
(such as a "reset" [action capsule](/paradigms/actions) that resets the state of several capsules at once).

<Warning>
  _Do not_ use transactions to update _related or derived_ states!
  For example, _do not_ make a capsule for a list of items
  paired with another capsule that stores the state of a set of the current "favorite" items.
  Doing so distributes one state across multiple sources, which is an anti-pattern in general. 
  Instead, you should have a `List<(Item, FavoritedStatus)>` or similar that uses data composition.
  Then, you can put your derived states in other capsules (such as a list of only favorited items).
</Warning>

Only one side effect transaction may run at a time, but transactions may be _nested_ such that
you can run multiple other smaller transactions within the context of one overarching transaction.
For example, two different capsules can update a few other capsules in their own transactions,
and then another capsule can come along and aggregate both of those capsules in its own transaction!
This allows each capsule to focus solely on the data it operates on (and nothing more),
rather than worrying about where/how it is used.

<Info>
  If you are familiar with them, reentrant mutexes share some similarities to nested transactions;
  in fact, transactions are on top of a reentrant mutex in ReArch for Rust!
</Info>

Without further ado, here is an example properly using transactions:
<CodeGroup title="Using side effect transactions">
  ```dart
  (
    int, {
    void Function() increment,
    void Function() reset,
  }) fooCapsule(CapsuleHandle use) {
    final (state, setState) = use.state(0);
    return (
      state,
      increment: () => setState(state + 1),
      reset: () => setState(0)
    );
  }

  (
    int, {
    void Function() increment,
    void Function() reset,
  }) barCapsule(CapsuleHandle use) {
    final (state, setState) = use.state(0);
    return (
      state,
      increment: () => setState(state + 1),
      reset: () => setState(0)
    );
  }

  void Function() resetAction(CapsuleHandle use) {
    final resets = [use(fooCapsule).reset, use(barCapsule).reset];
    final runTxn = use.transactionRunner();
    return () => runTxn(() {
          for (final reset in resets) {
            reset();
          }
        });
  }
  ```

  ```rust
  fn foo_capsule(
      CapsuleHandle { register, .. }: CapsuleHandle,
  ) -> (u32, impl CData + Fn(), impl CData + Fn()) {
      let (state, set_state) = register(effects::state::<Cloned<_>>(0));
      (
          state,
          {
              let set_state = set_state.clone();
              move || set_state(state + 1)
          },
          move || set_state(0),
      )
  }

  fn bar_capsule(
      CapsuleHandle { register, .. }: CapsuleHandle,
  ) -> (u32, impl CData + Fn(), impl CData + Fn()) {
      let (state, set_state) = register(effects::state::<Cloned<_>>(0));
      (
          state,
          {
              let set_state = set_state.clone();
              move || set_state(state + 1)
          },
          move || set_state(0),
      )
  }

  fn reset_action(CapsuleHandle { mut get, register }: CapsuleHandle) -> impl CData + Fn() {
      let reset_foo = get(foo_capsule).2;
      let reset_bar = get(bar_capsule).2;
      let run_txn = register.raw(()).2; // third element of returned tuple is an Fn that runs txns
      move || {
          let reset_foo = reset_foo.clone();
          let reset_bar = reset_bar.clone();
          run_txn(Box::new(move || {
              reset_foo();
              reset_bar();
          }));
      }
  }
  ```
</CodeGroup>


## Side Effect Library
See the side effect library on the left sidebar for documentation
on some of the builtin side effects!


## Creating Custom Side Effects
Help is wanted for this section!

In the meantime, take a peak at the source code for the builtin side effects,
as a lot of them use composition under the hood and are a good starting point.
