What is react-redux?
The react-redux package is the official React bindings for Redux. It allows React components to read data from a Redux store, and dispatch actions to the store to update data.
What are react-redux's main functionalities?
Provider Component
The Provider component makes the Redux store available to any nested components that need to access the Redux store.
{"import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './reducers';
import App from './App';
const store = createStore(rootReducer);
const rootElement = document.getElementById('root');
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
rootElement
);"}
connect Function
The connect function connects a React component to the Redux store. It can map state and dispatch to the props of the component.
{"import { connect } from 'react-redux';
import { increment, decrement } from './actionCreators';
function Counter({ count, increment, decrement }) {
return (
<div>
<button onClick={decrement}>-</button>
<span>{count}</span>
<button onClick={increment}>+</button>
</div>
);
}
const mapStateToProps = state => ({
count: state.count
});
const mapDispatchToProps = {
increment,
decrement
};
export default connect(mapStateToProps, mapDispatchToProps)(Counter);"}
useSelector Hook
The useSelector hook allows you to extract data from the Redux store state, using a selector function.
{"import { useSelector } from 'react-redux';
function MyComponent() {
const data = useSelector(state => state.data);
return <div>{data}</div>;
}"}
useDispatch Hook
The useDispatch hook returns a reference to the dispatch function from the Redux store. You can use it to dispatch actions.
{"import { useDispatch } from 'react-redux';
import { myAction } from './actionCreators';
function MyComponent() {
const dispatch = useDispatch();
return (
<button onClick={() => dispatch(myAction())}>Dispatch Action</button>
);
}"}
Other packages similar to react-redux
mobx-react
MobX-react is a package that provides React bindings for MobX. MobX is a state management library that uses observables to reactively update the UI when state changes. It is conceptually different from Redux and does not use a single store or reducers, but it provides a similar capability to reactively manage state in a React application.
zustand
Zustand is a small, fast, and scalable bearbones state-management solution using simplified flux principles. It is not tied to React and does not use reducers; instead, it works with a mutable state and provides a simple and intuitive API. It's more straightforward than Redux and can be an alternative for smaller applications or for developers who prefer a less boilerplate code approach.
recoil
Recoil is a state management library for React developed by Facebook. It provides several capabilities similar to Redux, such as shared state between components, but it uses a different approach based on atoms (units of state) and selectors (pure functions to derive state). Recoil works with React's concurrent mode out of the box and is meant to be more efficient and easier to use with React's functional components.
context-state
Context-state is a library that leverages the React Context API to manage state. It is a simpler alternative to Redux that might be suitable for applications with a less complex state management requirement. It does not have middleware or the same level of devtools support as Redux, but it can be a lightweight solution for simpler use cases.
react-redux
Higher-order React components for Redux.
What you get from react-redux
is for React.
For React Native, import from react-redux/native
instead.
Note: There is a project called “redux-react” on NPM that is completely unrelated to the official bindings. This documentation (and any other official Redux documentation) is for react-redux
.
Quick Start
React bindings for Redux embrace the idea of dividing “smart” and “dumb” components.
It is advisable that only top-level components of your app (such as route handlers, for example) are aware of Redux. Components below them should be “dumb” and receive all data via props.
| Location | Use React-Redux | To read data, they | To change data, they |
---|
“Smart” Components | Top level, route handlers | Yes
| Subscribe to Redux state | Dispatch Redux actions |
“Dumb” Components | Middle and leaf components | No
| Read data from props | Invoke callbacks from props |
“Dumb” component is unaware of Redux
Let’s say we have a <Counter />
“dumb” component with a number counter
prop, and an increment
function prop that it will call when user presses an “Increment” button:
import { Component } from 'react';
export default class Counter extends Component {
render() {
return (
<button onClick={this.props.increment}>
{this.props.counter}
</button>
);
}
}
“Smart” component is connect()
-ed to Redux
Here’s how we hook it up to the Redux Store.
We will use connect()
function provided by react-redux
to turn a “dumb” Counter
into a smart component. With the current API, we’ll need to add an intermediate CounterContainer
component, but we will soon make connect
API more powerful so this won’t be required. The connect()
function lets you specify which exactly state from the Redux store your component wants to track. This lets you subscribe on any level of granularity.
Our CounterContainer
that’s necessary to hook Counter
up to a Redux store looks like this:
(This will be much less verbose in the next versions.)
import { Component } from 'react';
import { connect } from 'react-redux';
import Counter from '../components/Counter';
import { increment } from './actionCreators';
function select(state) {
return {
counter: state.counter
};
}
class CounterContainer extends Component {
render() {
const { dispatch, counter } = this.props;
return (
<Counter counter={counter}
increment={() => dispatch(increment())} />
);
}
}
export default connect(select)(CounterContainer);
As you can see, action creators in Redux just return actions, but we need to manually “bind” them to the dispatch
function for our Redux store. Why don’t we bind action creators to a store right away? This is because of the so-called “universal” apps that need to render on the server. They would have a different store instance for every request, so we don’t know the store instance during the definition!
Binding many action creators
Binding can get cumbersome, so Redux provides a bindActionCreators
helper to turn many action creator methods into an object with methods called the same, but bound to a particular dispatch
function:
import { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as CounterActionCreators from './actionCreators';
import Counter from '../components/Counter';
function select(state) {
return {
counter: state.counter
};
}
class CounterContainer extends Component {
render() {
const { dispatch, counter } = this.props;
return (
<Counter counter={counter}
{...bindActionCreators(CounterActionCreators, dispatch)} />
);
}
}
export default connect(select)(CounterContainer);
You can have many connect()
-ed components in your app at any depth, and you can even nest them. It is however preferable that you try to only connect()
top-level components such as route handlers, so the data flow in your application stays predictable.
Injecting Redux store
Finally, how do we actually hook it up to a Redux store? We need to create the store somewhere at the root of our component hierarchy. For client apps, the root component is a good place. For server rendering, you can do this in the request handler.
The trick is to wrap the whole view hierarchy into <Provider>{() => ... }</Provider>
where Provider
is imported from react-redux
. One gotcha is that the child of Provider
must be a function. This is to work around an issue with how context (undocumented feature we have to rely on to pass Redux data to components below) works in React 0.13. In React 0.14, you will be able to put your view hierarchy in <Provider>
without wrapping it into a function.
import { Component } from 'react';
import { Provider } from 'react-redux';
class App extends Component {
render() {
}
}
const targetEl = document.getElementById('root');
React.render((
<Provider store={store}>
{() => <App />}
</Provider>
), targetEl);
API
connect
export default connect(select)(MyComponent);
Returns a component class that injects the Redux Store’s dispatch
as a prop into Component
so it can dispatch Redux actions.
The returned component also subscribes to the updates of Redux store. Any time the state changes, it calls the select
function passed to it. The selector function takes a single argument of the entire Redux store’s state and returns an object to be passed as props. Use reselect to efficiently compose selectors and memoize derived data.
Both dispatch
and every property returned by select
will be provided to your Component
as props
.
It is the responsibility of a Smart Component to bind action creators to the given dispatch
function and pass those
bound creators to Dumb Components. Redux provides a bindActionCreators
to streamline the process of binding action
creators to the dispatch function.
To use connect()
, the root component of your app must be wrapped into <Provider>{() => ... }</Provider>
before being rendered.
See the usage example in the quick start above.
Provider
<Provider store={store}>
{() => <MyRootComponent>}
</Provider>
The Provider
component takes a store
prop and a function as a child with your root
component. The store
is then passed to the child via React's context
. This is the entry point for Redux and must be
present in order to use the connect
component.
License
MIT