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
selectorshould be pure since it is potentially executed multiple times and at arbitrary points in time. - The
selectoris approximately equivalent to themapStateToPropsargument of connect conceptually. - The
selectorwill be called with the entire ReduxStorestate as its only argument. - The
selectorwill 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
Countercomponent is rendered as the descendant of a ReduxProvider component that is wired up to a ReduxStoreinstance with aCounterStateinstance 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
useSelectorunless 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));
}
}