useSelector<TReduxState, TValue> function

TValue useSelector<TReduxState, TValue>(
  1. TValue selector(
    1. TReduxState state
    ), [
  2. bool equalityFn(
    1. TValue tNextValue,
    2. 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 the mapStateToProps argument of connect conceptually.
  • The selector will be called with the entire Redux Store 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 Redux Store instance with a CounterState instance containing a field called count.

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));
  }
}