Guides

Overriding Component UI

This is an exploration of overriding a component's UI within Flutter Forge.


There are two main methods of overriding a component's UI within Flutter Forge.

  • the optional builder constructor parameter
  • inherit from the component and override the build method

Optional builder parameter

This is probably the more idiomatic approach in the Flutter community. But if you don't like it for some reason you can always use the "Inherit & Override" approach.

// defined somewhere up the hierarchy (possibly even globally)
counterStore = Store(
	  initialState: const CounterState(count: 0),
	  reducer: counterReducer,
	  environment: CounterEnvironment(),
	);

Counter(
	store: counterStore,
	builder: (context, store, viewStore) {
	  return Column(children: [
		Rebuilder(
			store: store,
			builder: (context, state, child) {
			  return Text(
				'${state.count}',
				style: Theme.of(context).textTheme.displayLarge,
			  );
			}),
		ElevatedButton(
			onPressed: () => viewStore
				.send(counter.CounterIncrementButtonTapped()),
			child: const Text("overriden ui - increment"))
	  ]);
	}),

In this example we simply construct an instance of the Counter component while providing the optional builder function which if present is responsible for returning the widget tree for that component. Allowing you to override the UI of the component.

Note: When people define their components. They need to make sure that they proxy the builder parameter through the constructor otherwise this option won't be available to consumers of their components.

class Counter
    extends ComponentWidget<CounterState, CounterEnvironment, CounterAction> {
  const Counter({super.key, required super.store, super.builder});

In the above we can see that we are passing the two optional parameters key & builder through to the base class by using super.key & super.builder respectively.

Inherit & Override build

In the following example we simply create a class called CounterWithOverridenUi that extends from Counter and @override the build method.

class CounterWithOverridenUi extends Counter {
  CounterWithOverridenUi({super.key, required super.store, super.builder});

  @override
  Widget build(context, viewStore) {
    return Column(children: [
      Rebuilder(
          store: store,
          builder: (context, state, child) {
            return Text(
              '${state.count}',
              style: Theme.of(context).textTheme.displayLarge,
            );
          }),
      ElevatedButton(
          onPressed: () =>
              viewStore.send(counter.CounterIncrementButtonTapped()),
          child: const Text("overriden ui - increment"))
    ]);
  }
}

This makes it so that CounterWithOverridenUi is a component of the same CounterState, CounterEnvironment, and CounterAction that the Counter widget is. But it uses the overridden build method for the UI rather than the build method provided by the Counter widget.

Previous
Loading Data Async