Security News
ESLint is Now Language-Agnostic: Linting JSON, Markdown, and Beyond
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
react-redux
Advanced tools
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.
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>
);
}"}
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 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 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 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.
Official React bindings for Redux.
Performant and flexible.
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 forreact-redux
.
npm install --save react-redux
Be careful! “React” goes first.
There is a project called redux-react
, but it is completely unrelated.
React Redux requires React 0.13 or later.
What you get from react-redux
is for React.
For React Native, import from react-redux/native
instead.
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 |
Let’s say we have a <Counter />
“dumb” component with a number value
prop, and an onIncrement
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.onIncrement}>
{this.props.value}
</button>
);
}
}
connect()
-ed to ReduxHere’s how we hook it up to the Redux Store.
We will use the connect()
function provided by react-redux
to turn a “dumb” Counter
into a smart component. The connect()
function lets you specify which exact state from the Redux store your component wants to track. This lets you subscribe on any level of granularity.
containers/CounterContainer.js
import { Component } from 'react';
import { connect } from 'react-redux';
import Counter from '../components/Counter';
import { increment } from '../actionsCreators';
// Which part of the Redux global state does our component want to receive as props?
function mapStateToProps(state) {
return {
value: state.counter
};
}
// Which action creators does it want to receive by props?
function mapDispatchToProps(dispatch) {
return {
onIncrement: () => dispatch(increment())
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Counter);
// You can also pass an object instead of defining `mapDispatchToProps`:
// export default connect(mapStateToProps, CounterActionCreators)(Counter);
// Or you can pass `dispatch` down as a prop if you omit `mapDispatchToProps`:
// export default connect(mapStateToProps)(Counter);
// See more recipes in detailed connect() examples below.
Whether to put the connect()
call in the same file as the “dumb” component, or separately, is up to you.
Ask yourself whether you'd want to reuse this component but bind it to different data, or not.
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.
You might have noticed that we used parens twice when calling connect()
. This is called partial application, and it lets people
use ES7’s proposed decorator syntax:
// Unstable syntax! It might change or break in production.
@connect(mapStateToProps)
export default class CounterContainer { ... }
Don’t forget decorators are experimental! They desugar to function calls anyway as the example above demonstrates.
This is the most basic usage, but connect()
supports many other patterns: just passing the vanilla dispatch()
function down, binding multiple action creators, passing them in an actions
prop, selecting parts of state and binding action creators depending on props
, and so on. Check out the connect()
docs below to learn more.
Finally, how do we actually hook it up to the 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 a <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 about 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);
<Provider store>
Makes the Redux store available to the connect()
calls in the component hierarchy below. Normally, you can’t use connect()
without wrapping the root component in <Provider>
. (If you really need to, you can manually pass store
as a prop to every connect()
ed component, but we only recommend to do this for stubbing store
in unit tests, or in non-fully-React codebases. Normally, you should just use <Provider>
.)
store
: (Redux Store): The single Redux store in your application.children
: (Function): Unlike most React components, <Provider>
accepts a function as a child with your root component. This is a temporary workaround for a React 0.13 context issue, which will be fixed when React 0.14 comes out.React.render(
<Provider store={store}>
{() => <MyRootComponent />}
</Provider>,
rootEl
);
Router.run(routes, Router.HistoryLocation, (Handler, routerState) => { // note "routerState" here
React.render(
<Provider store={store}>
{() => <Handler routerState={routerState} />} // note "routerState" here: important to pass it down
</Provider>,
document.getElementById('root')
);
});
React.render(
<Provider store={store}>
{() => <Router history={history}>...</Router>}
</Provider>,
targetEl
);
connect([mapStateToProps], [mapDispatchToProps], [mergeProps])
Connects a React component to a Redux store.
[mapStateToProps(state, [ownProps]): stateProps
] (Function): If specified, the component will subscribe to Redux store updates. Any time it updates, mapStateToProps
will be called. Its result must be a plain object, and it will be merged into the component’s props. If you omit it, the component will not be subscribed to the Redux store. If ownProps
is specified as a second argument, then mapStateToProps
will be re-invoked whenever the component receives new props.
[mapDispatchToProps(dispatch, [ownProps]): dispatchProps
] (Object or Function): If an object is passed, each function inside it will be assumed to be a Redux action creator. An object with the same function names, but bound to a Redux store, will be merged into the component’s props. If a function is passed, it will be given dispatch
. It’s up to you to return an object that somehow uses dispatch
to bind action creators in your own way. (Tip: you may use the bindActionCreators()
helper from Redux.) If you omit it, the default implementation just injects dispatch
into your component’s props. If ownProps
is specified as a second argument, then mapDispatchToProps
will be re-invoked whenever the component receives new props.
[mergeProps(stateProps, dispatchProps, ownProps): props
] (Function): If specified, it is passed the result of mapStateToProps()
, mapDispatchToProps()
, and the parent props
. The plain object you return from it will be passed as props to the wrapped component. You may specify this function to select a slice of the state based on props, or to bind action creators to a particular variable from props. If you omit it, Object.assign({}, ownProps, stateProps, dispatchProps)
is used by default.
A React component class that injects state and action creators into your component according to the specified options.
It needs to be invoked two times. The first time with its arguments described above, and a second time, with the component: connect(mapStateToProps, mapDispatchToProps, mergeProps)(MyComponent)
.
The mapStateToProps
function takes a single argument of the entire Redux store’s state and returns an object to be passed as props. It is often called a selector. Use reselect to efficiently compose selectors and compute derived data.
To use connect()
, the root component of your app must be wrapped into <Provider>{() => ... }</Provider>
before being rendered. You may also pass store
as a prop to the connect()
ed component, but it's not recommended, because it's just too much trouble. Only do this for non-fully-React codebases or to stub the store in a unit test.
dispatch
and don't listen to storeexport default connect()(TodoApp);
dispatch
and every field in the global stateDon’t do this! It kills any performance optimisations because
TodoApp
will rerender after every action.
It’s better to have more granularconnect()
on several components in your view hierarchy.
export default connect(state => state)(TodoApp);
dispatch
and todos
function mapStateToProps(state) {
return { todos: state.todos };
}
export default connect(mapStateToProps)(TodoApp);
todos
and all action creators (addTodo
, completeTodo
, ...)import * as actionCreators from './actionCreators';
function mapStateToProps(state) {
return { todos: state.todos };
}
export default connect(mapStateToProps, actionCreators)(TodoApp);
todos
and all action creators (addTodo
, completeTodo
, ...) as actions
import * as actionCreators from './actionCreators';
import { bindActionCreators } from 'redux';
function mapStateToProps(state) {
return { todos: state.todos };
}
function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators(actionCreators, dispatch) };
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp);
todos
and a specific action creator (addTodo
)import { addTodo } from './actionCreators';
import { bindActionCreators } from 'redux';
function mapStateToProps(state) {
return { todos: state.todos };
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ addTodo }, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp);
todos
, todoActionCreators as todoActions
, and counterActionCreators as counterActions
import * as todoActionCreators from './todoActionCreators';
import * as counterActionCreators from './counterActionCreators';
import { bindActionCreators } from 'redux';
function mapStateToProps(state) {
return { todos: state.todos };
}
function mapDispatchToProps(dispatch) {
return {
todoActions: bindActionCreators(todoActionCreators, dispatch),
counterActions: bindActionCreators(counterActionCreators, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp);
todos
, and todoActionCreators and counterActionCreators together as actions
import * as todoActionCreators from './todoActionCreators';
import * as counterActionCreators from './counterActionCreators';
import { bindActionCreators } from 'redux';
function mapStateToProps(state) {
return { todos: state.todos };
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp);
todos
, and all todoActionCreators and counterActionCreators directly as propsimport * as todoActionCreators from './todoActionCreators';
import * as counterActionCreators from './counterActionCreators';
import { bindActionCreators } from 'redux';
function mapStateToProps(state) {
return { todos: state.todos };
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp);
todos
of a specific user depending on propsimport * as actionCreators from './actionCreators';
function mapStateToProps(state, ownProps) {
return { todos: state.todos[ownProps.userId] };
}
export default connect(mapStateToProps)(TodoApp);
todos
of a specific user depending on props, and inject props.userId
into the actionimport * as actionCreators from './actionCreators';
function mapStateToProps(state) {
return { todos: state.todos };
}
function mergeProps(stateProps, dispatchProps, ownProps) {
return Object.assign({}, ownProps, {
todos: stateProps.todos[ownProps.userId],
addTodo: (text) => dispatchProps.addTodo(ownProps.userId, text)
});
}
export default connect(mapStateToProps, actionCreators, mergeProps)(TodoApp);
Make sure to check out Troubleshooting Redux first.
See the link above. In short,
mapDispatchToProps
argument to connect()
or with the bindActionCreators()
method, or that you manually call dispatch()
. Just calling your MyActionCreators.addTodo()
function won’t work because it just returns an action, but does not dispatch it.If you’re using React Router 0.13, you might bump into this problem. The solution is simple: whenever you use <RouteHandler>
or the Handler
provided by Router.run
, pass the router state to it.
Root view:
Router.run(routes, Router.HistoryLocation, (Handler, routerState) => { // note "routerState" here
React.render(
<Provider store={store}>
{() => <Handler routerState={routerState} />} // note "routerState" here
</Provider>,
document.getElementById('root')
);
});
Nested view:
render() {
// Keep passing it down
return <RouteHandler routerState={this.props.routerState} />;
}
Conveniently, this gives your components access to the router state! You can also upgrade to React Router 1.0 which shouldn’t have this problem. (Let us know if it does!)
If you have context issues,
<Provider>
.<Provider>{() => routes}</Provider>
won’t work. Due to the way context works in React 0.13, it’s important that the <Provider>
children are created inside that function. Just referencing an outside variable doesn’t do the trick. Instead of <Provider>{() => routes}</Provider>
, write <Provider>{createRoutes}</Provider>
where createRoutes()
is a function that actually creates (and returns) the route configuration.If you’re using React for web, this usually means you have a duplicate React. Follow the linked instructions to fix this.
If you’re using React Native, make sure you’re importing react-redux/native
both for <Provider>
and any connect()
call. Importing from react-redux
will not work on React Native.
MIT
FAQs
Official React bindings for Redux
The npm package react-redux receives a total of 6,236,845 weekly downloads. As such, react-redux popularity was classified as popular.
We found that react-redux demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
Security News
Members Hub is conducting large-scale campaigns to artificially boost Discord server metrics, undermining community trust and platform integrity.
Security News
NIST has failed to meet its self-imposed deadline of clearing the NVD's backlog by the end of the fiscal year. Meanwhile, CVE's awaiting analysis have increased by 33% since June.