Skip to content

Latest commit

 

History

History
148 lines (112 loc) · 5.38 KB

quick-start.md

File metadata and controls

148 lines (112 loc) · 5.38 KB

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.

“Smart” Components “Dumb” Components
Location Top level, route handlers Middle and leaf components
Aware of Redux Yes No
To read data Subscribe to Redux state Read data from props
To change data Dispatch Redux actions Invoke callbacks from props

“Dumb” components are unaware of Redux

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

“Smart” components are connect()-ed to Redux

Here’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.

Nesting

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.

Support for Decorators

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.

Additional Flexibility

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.

Injecting Redux Store

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