useSelector<TReduxState, TValue> function
- TValue selector(
- TReduxState state
- bool equalityFn(
- TValue tNextValue,
- TValue tPrevValue
A hook that allows you to extract data from the Redux Store
state, using a selector
function.
The use of this hook will also subscribe your component to the Redux Store
, and run your selector
whenever
an action is dispatched.
- The
selector
should be pure since it is potentially executed multiple times and at arbitrary points in time. - The
selector
is approximately equivalent to themapStateToProps
argument of connect conceptually. - The
selector
will be called with the entire ReduxStore
state as its only argument. - The
selector
will be run whenever the function component renders.
By default, the return value of selector
is compared using strict (===
) equality. If you want to
customize how equality is defined, pass a comparator function to the equalityFn
argument.
If you need to use a selector with custom Context, use createSelectorHook instead.
See the react-redux JS documentation for more details.
Example
This example assumes that your
Counter
component is rendered as the descendant of a ReduxProvider component that is wired up to a ReduxStore
instance with aCounterState
instance containing a field calledcount
.
import 'package:over_react/over_react.dart';
import 'package:over_react/over_react_redux.dart';
import 'counter_state.dart';
mixin CounterProps on UiProps {}
UiFactory<CounterProps> Counter = uiFunction(
(props) {
final count = useSelector<CounterState, int>((state) => state.count);
return Dom.div()('The current count is $count');
},
$CounterConfig, // ignore: undefined_identifier
);
Multiple Selectors
If you need to use multiple selectors in a single component, use createSelectorHook to
shadow useSelector
as shown below to remove a bunch of unnecessary boilerplate as shown
in the example below.
Consider the previous example, but instead of only needing to access count
from the store,
you need to access count
, and two other field values as well. Using useSelector
for all
of these can get a little messy:
import 'package:over_react/over_react.dart';
import 'package:over_react/over_react_redux.dart';
import 'counter_state.dart';
mixin CounterProps on UiProps {}
UiFactory<CounterProps> Counter = uiFunction(
(props) {
final count = useSelector<CounterState, int>((state) => state.count);
final foo = useSelector<CounterState, String>((state) => state.foo);
final bar = useSelector<CounterState, Map>((state) => state.bar);
return Dom.div()('The current $foo count is $count. $bar my dude.');
},
$CounterConfig, // ignore: undefined_identifier
);
Instead of needing to declare those generic parameters each time on useSelector
, shadow it like so:
import 'package:over_react/over_react.dart';
import 'package:over_react/over_react_redux.dart';
import 'counter_state.dart';
/// All the types for state fields within `CounterState` will be inferred!
final useSelector = createSelectorHook<CounterState>();
mixin CounterProps on UiProps {}
UiFactory<CounterProps> Counter = uiFunction(
(props) {
final count = useSelector((state) => state.count);
final foo = useSelector((state) => state.foo);
final bar = useSelector((state) => state.bar);
return Dom.div()('The current $foo count is $count. $bar my dude.');
},
$CounterConfig, // ignore: undefined_identifier
);
CAUTION: Be sure to not export the shadowed value of
useSelector
unless you know exactly what you're doing, and the consumers of your library expect the hook to always have the context of the state you parameterize it with.
Related: useDispatch
Implementation
TValue useSelector<TReduxState, TValue>(
TValue Function(TReduxState state) selector, [
bool Function(TValue tNextValue, TValue tPrevValue)? equalityFn,
]) {
Object? /*[1]*/ jsSelector(Object? /*[1]*/ jsState) =>
DartValueWrapper.wrapIfNeeded(selector(DartValueWrapper.unwrapIfNeeded(jsState)));
_JsReduxStateEqualityFn? jsEqualityFn = equalityFn == null
? null
: allowInterop((nextJsValue, prevJsValue) =>
equalityFn(DartValueWrapper.unwrapIfNeeded(nextJsValue), DartValueWrapper.unwrapIfNeeded(prevJsValue)));
if (jsEqualityFn == null) {
return DartValueWrapper.unwrapIfNeeded(_jsUseSelector(allowInterop(jsSelector)));
} else {
return DartValueWrapper.unwrapIfNeeded(_jsUseSelector(allowInterop(jsSelector), jsEqualityFn));
}
}