如何使用 connect w/Redux 从 this.props 获得简单的分派?

我连接了一个简单的 React 组件(映射一个简单的数组/状态)。为了避免引用商店的上下文,我想要一种直接从道具获得“分派”的方法。我见过其他人使用这种方法,但由于某些原因无法使用它:)

下面是我目前使用的每个 npm 依赖项的版本

"react": "0.14.3",
"react-redux": "^4.0.0",
"react-router": "1.0.1",
"redux": "^3.0.4",
"redux-thunk": "^1.0.2"

下面是组件 w/connect 方法

class Users extends React.Component {
render() {
const { people } = this.props;
return (
<div>
<div>{this.props.children}</div>
<button onClick={() => { this.props.dispatch({type: ActionTypes.ADD_USER, id: 4}); }}>Add User</button>
</div>
);
}
};


function mapStateToProps(state) {
return { people: state.people };
}


export default connect(mapStateToProps, {
fetchUsers
})(Users);

如果你需要看到减速器(没有什么令人兴奋的,但它在这里)

const initialState = {
people: []
};


export default function(state=initialState, action) {
if (action.type === ActionTypes.ADD_USER) {
let newPeople = state.people.concat([{id: action.id, name: 'wat'}]);
return {people: newPeople};
}
return state;
};

如果您需要查看我的路由器是如何配置的 w/reducx

const createStoreWithMiddleware = applyMiddleware(
thunk
)(createStore);


const store = createStoreWithMiddleware(reducers);


var Route = (
<Provider store={store}>
<Router history={createBrowserHistory()}>
{Routes}
</Router>
</Provider>
);

更新

看起来,如果在连接中省略自己的分派(目前在上面显示的是 fetchUsers) ,就会得到免费的分派(只是不确定这是否是通常设置 w/异步操作的工作方式)。人们是混合搭配,还是一切都是或者什么都不是?

[ mapDispatchToProps ]

67333 次浏览

You can usually mix and match based on what you'd like.

You can pass dispatch on as a prop if that is what you want:

export default connect(mapStateToProps, (dispatch) => ({
...bindActionCreators({fetchUsers}, dispatch), dispatch
}))(Users);

I'm not sure how fetchUsers is used (as an async function?), but you would usually use something like bindActionCreators to auto-bind dispatch and then you would not have to worry about using dispatch directly in connected components.

Using dispatch directory sort of couples the dumb, stateless component with redux. Which can make it less portable.

While you could pass dispatch down as part of dispatchToProps, I would recommend avoiding accessing the store or dispatch directly from within your components. It seems like you would be better served by passing in a bound action creator in connect's 2nd argument dispatchToProps

See an example I posted here https://stackoverflow.com/a/34455431/2644281 of how to pass down an "already bound action creator" this way your components don't need to directly know about or depend on the store/dispatch.

Sorry to be brief. I'll update w/ more info.

By default mapDispatchToProps is just dispatch => ({ dispatch }).
So if you don't specify the second argument to connect(), you'll get dispatch injected as a prop in your component.

If you pass a custom function to mapDispatchToProps, you can do anything with the function.
A few examples:

// inject onClick
function mapDispatchToProps(dispatch) {
return {
onClick: () => dispatch(increment())
};
}


// inject onClick *and* dispatch
function mapDispatchToProps(dispatch) {
return {
dispatch,
onClick: () => dispatch(increment())
};
}

To save you some typing Redux provides bindActionCreators() that lets you turn this:

// injects onPlusClick, onMinusClick
function mapDispatchToProps(dispatch) {
return {
onPlusClick: () => dispatch(increment()),
onMinusClick: () => dispatch(decrement())
};
}

into this:

import { bindActionCreators } from 'redux';


// injects onPlusClick, onMinusClick
function mapDispatchToProps(dispatch) {
return bindActionCreators({
onPlusClick: increment,
onMinusClick: decrement
}, dispatch);
}

or even shorter when prop names match action creator names:

// injects increment and decrement
function mapDispatchToProps(dispatch) {
return bindActionCreators({ increment, decrement }, dispatch);
}

If you'd like you can definitely add dispatch there by hand:

// injects increment, decrement, and dispatch itself
function mapDispatchToProps(dispatch) {
return {
...bindActionCreators({ increment, decrement }), // es7 spread syntax
dispatch
};
}

There's no official advise on whether you should do this or not. connect() usually serves as the boundary between Redux-aware and Redux-unaware components. This is why we usually feel that it doesn't make sense to inject both bound action creators and dispatch. But if you feel like you need to do this, feel free to.

Finally, the pattern you are using right now is a shortcut that's even shorter than calling bindActionCreators. When all you do is return bindActionCreators, you can omit the call so instead of doing this:

// injects increment and decrement
function mapDispatchToProps(dispatch) {
return bindActionCreators({ increment, decrement }, dispatch);
}


export default connect(
mapStateToProps,
mapDispatchToProps
)(App);

can be written as this

export default connect(
mapStateToProps,
{ increment, decrement } // injects increment and decrement
)(App);

However you'll have to give up that nice short syntax whenever you want something more custom, like passing dispatch as well.