Core concepts
State
The following is an exploration of what State is conceptually and how they are used in Flutter Forge.
Concept
State is effectively all the types of data that our Widget cares about in terms of presenting as well as interacting. In the case of a simple Counter Component, this is just the count
. In more complex components that are based on user interactions that can fail, this could be data keeping track of the status of a process, or a variety of other things.
In Practice
We generally interact with state in the following ways.
Define state
To define State for a Component we simply define a @immutable
class that generally extendsEquatable
as State needs to be value equatable.
In the following example we define a State class named CounterWidgetState
that holds a single value of count
. Note: We have to make the State Equatable
so that Flutter Forge can properly tell when the state has changed. If you aren't familiar with the equatable package, it is simply a package that streamlines the process of making a class Equatable
via the required props
getter.
@immutable
class CounterWidgetState extends Equatable {
const State({required this.count});
final int count;
@override
List<Object> get props => [count];
}
Note: Adding copyWith
to the State class is very common as it eases making changes to the State in an immutable fashion within the Reducer. Please also see the section below, Mutate State, to gain more context.
Access state
Generally you access the State by using either the Rebuilder
or SelectRebuild
that facilitate rebuilding a portion of your Widget tree when the State changes. It exposes the read-only, managed State instance to the builder
function via the state
parameter.
Rebuilder(
store: store,
builder: (context, state, child) {
return Text(
'${state.count}',
style: Theme.of(context).textTheme.headline4,
);
}),
In the above example we are accessing the CounterWidgetState
's count
property with or Text
widget via state.count
.
Mutate state
The other way we interact with State is by making changes to it. In Flutter Forge the only way to make changes to the state is through the Store and in turn the Reducer. The Reducer`s job is to interpret Actions and compute the new instance of State.
final counterReducer = Reducer<CounterWidgetState, CounterWidgetEnvironment, CounterWidgetAction>(
(state, action) {
switch (action) {
case CounterWidgetIncrementButtonTapped _:
return ReducerTuple(CounterWidgetState(count: state.count + 1), []);
}
});
In the above example we have a simple Reducer for the Counter Component. It takes in Actions and checks if the action is a CounterWidgetIncrementButtonTapped
action. If it is then it returns a ReducerTuple
containing a newly constructed instance of the CounterWidgetState
with a count
equal to the previous count
, plus one.