Logo

Widgets

When creating a UI, it makes sense to boil down individual views to their functional requirements:

  • displaying certain data/state
  • modifying certain data/state
  • wrapping around/displaying other views

As such, UI is often described as a function of state; ReArch takes this one step further by classifying UI as a function of state and any side effect(s).

Sound familiar? It's because capsules are also functions of state and side effect(s)! Just like capsules, you define widgets as functions consuming state and side effect(s).

Full Example#

First, let's define some capsules for use in our widgets. Capsules can be defined in the same file as widgets, or in completely separate file(s).

Defining some capsules
String _salutationCapsule(CapsuleHandle _) => 'Hello';

(String, void Function(String)) firstNameCapsule(CapsuleHandle use) => use.state('Alice');

String greetingCapsule(CapsuleHandle use) {
  return '${use(_salutationCapsule)} ${use(firstNameCapsule).$1}!';
} 

Next, let's use these capsules in a custom widget.

Defining a custom widget
// Check out Unnested!
// ReArch and Unnested are like peanut butter and jelly, as seen here.
@rearchWidget
Widget myAppBody(WidgetHandle use) {
  return Unnest()
      .scaffold(appBar: AppBar(title: Text(use(greetingCapsule))))
      .center()
      .textField(onChanged: use(firstNameCapsule).$2);
}

// ...

MyAppPage(child: const MyAppBody());

Parameters#

Any parameters you add to @rearchWidget functions are automatically passed onto the generated widget's constructor, similar to @factoryCapsule.

Passing custom parameters to a stateful widget
// Here's a modified version of the above example.
@rearchWidget
Widget greetingWidget(
  WidgetHandle use, {
  required String greeting,
  required Widget child,
}) {
  return Column(children: [
    Text('$greeting, ${use(firstNameCapsule).$1}!'),
    child,
  ]);
}

// ...

const GreetingWidget(
  greeting: 'Hey',
  child: Text('Some child widget'),
);

You can even use @rearchWidget to create simple stateless widgets too, without the boilerplate; Just don't include the WidgetHandle parameter!

Here's an example creating a stateless widget with some parameters.

Stateless widget with parameters
@rearchWidget
Widget myTextCard(BuildContext context, {required String title}) {
  return Card(
    child: Text(
      title,
      style: Theme.of(context).textTheme.headlineLarge,
    ),
  );
}

Notice how we depended on the BuildContext above. You can also depend on the widget's key too!

Finally, here's an example creating a simple reusable widget without any parameters.

Stateless widget without parameters
@rearchWidget
Widget myIcon() {
  return Icon(Icons.clock, color: Colors.purple);
}

The RearchBuilder#

The RearchBuilder enables you to delegate building a widget to a callback that has access to a WidgetHandle and a BuildContext. This can be useful when you want to simply get a new WidgetHandle inline with some other widgets when it might not make sense to make an entirely new widget (just like Flutter's Builder itself).

MyWidget(
  child: RearchBuilder(
    builder: (context, use) {
      return Placeholder();
    },
  ),
);