Skip to content

Pass props into state selector #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,9 @@ Connects a React component to a Redux store.

#### Arguments

* [`mapStateToProps(state): 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.
* [`mapStateToProps(state, props): 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.

* [`mapDispatchToProps(dispatch): 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 [`bindActionCreators()`](http://gaearon.github.io/redux/docs/api/bindActionCreators.html) helper from Redux.) If you omit it, the default implementation just injects `dispatch` into your component’s props.
* [`mapDispatchToProps(dispatch, props): 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 [`bindActionCreators()`](http://gaearon.github.io/redux/docs/api/bindActionCreators.html) helper from Redux.) If you omit it, the default implementation just injects `dispatch` into your component’s props.

* [`mergeProps(stateProps, dispatchProps, parentProps): 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, `{ ...parentProps, ...stateProps, ...dispatchProps }` is used by default.

Expand Down
16 changes: 8 additions & 8 deletions src/components/createConnect.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ export default function createConnect(React) {
// Helps track hot reloading.
const version = nextVersion++;

function computeStateProps(context) {
function computeStateProps(context, props = {}) {
const state = context.store.getState();
const stateProps = finalMapStateToProps(state);
const stateProps = finalMapStateToProps(state, props);
invariant(
isPlainObject(stateProps),
'`mapStateToProps` must return an object. Instead received %s.',
Expand All @@ -45,9 +45,9 @@ export default function createConnect(React) {
return stateProps;
}

function computeDispatchProps(context) {
function computeDispatchProps(context, props = {}) {
const { dispatch } = context.store;
const dispatchProps = finalMapDispatchToProps(dispatch);
const dispatchProps = finalMapDispatchToProps(dispatch, props);
invariant(
isPlainObject(dispatchProps),
'`mapDispatchToProps` must return an object. Instead received %s.',
Expand Down Expand Up @@ -83,13 +83,13 @@ export default function createConnect(React) {
this.version = version;
this.setUnderlyingRef = ::this.setUnderlyingRef;

this.stateProps = computeStateProps(context);
this.dispatchProps = computeDispatchProps(context);
this.stateProps = computeStateProps(context, props);
this.dispatchProps = computeDispatchProps(context, props);
this.state = this.computeNextState();
}

recomputeStateProps() {
const nextStateProps = computeStateProps(this.context);
const nextStateProps = computeStateProps(this.context, this.props);
if (shallowEqual(nextStateProps, this.stateProps)) {
return false;
}
Expand All @@ -99,7 +99,7 @@ export default function createConnect(React) {
}

recomputeDispatchProps() {
const nextDispatchProps = computeDispatchProps(this.context);
const nextDispatchProps = computeDispatchProps(this.context, this.props);
if (shallowEqual(nextDispatchProps, this.dispatchProps)) {
return false;
}
Expand Down
24 changes: 24 additions & 0 deletions test/components/connect.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,30 @@ describe('React', () => {
).toNotThrow();
});

it('should pass the props into the state map', () => {
const store = createStore(() => ({
foo: 'bar',
baz: 42,
hello: 'world'
}));

@connect((state, {foo}) => ({ bar: foo }))
class Container extends Component {
render() {
return <div {...this.props} />;
}
}

const container = TestUtils.renderIntoDocument(
<Provider store={store}>
{() => <Container foo={50} />}
</Provider>
);

const div = TestUtils.findRenderedDOMComponentWithTag(container, 'div');
expect(div.props.bar).toEqual(50);
})

it('should subscribe to the store changes', () => {
const store = createStore(stringBuilder);

Expand Down