Mat*_*ieu 8 javascript reactjs redux
在我的redux容器中,我必须从商店中发送相当复杂的操作,从中获取大量属性.如果不破坏性能,我找不到合适的模式来解决问题.
我们以一个只包含Send按钮发送消息的容器为例:
(对于这样一个小例子,以下任何一种方法都能很好地工作,我只是想说明我在更大容器中遇到的问题.)
function mapStateToProps(state) {
return {
user: selectors.selectedUser(state),
title: selectors.title(state),
message: selectors.message(state),
};
}
function dispatchProps(state) {
return {
onClickSend: function(user, title, message) {
actions.sendMessage({user, title, message});
}
};
}
Run Code Online (Sandbox Code Playgroud)
如果我这样做,我的简单发送按钮必须知道很多无用的属性:
SendBtn.propTypes = {
user: PropTypes.string,
title: PropTypes.string,
message: PropTypes.string,
onClickSend: PropTypes.func,
}
Run Code Online (Sandbox Code Playgroud)
并且还要使用所有这些道具调用onClickSend:
onClickSend(user, title, message)
Run Code Online (Sandbox Code Playgroud)
这对于发送按钮来说太过分了.按钮应该只知道它onClickSend在我们点击它时必须调用,这个组件是一个简单的按钮.它不应该知道任何其他道具.此外,在更复杂的情况下,它可能不仅仅需要2个道具(标题和消息),而是5或10.
另一个问题是性能,每次我要修改消息或标题(每次击键时===),发送按钮将被重新渲染.
我的应用程序当前使用的当前方法是依赖mergeProps:
function mapStateToProps(state) {
return {
user: selectors.selectedUser(state),
title: selectors.title(state),
message: selectors.message(state),
};
}
function mergeProps(stateProps, dispatchProps, ownProps) {
const {user, title, message} = stateProps;
const newProps = {
onClickSend: actions.sendMessage.bind(null, {
user,
title,
message
});
};
return R.mergeAll([stateProps, dispatchProps, ownProps, newProps]);
}
Run Code Online (Sandbox Code Playgroud)
我发现这种方法更好,因为发送按钮只需要知道它必须触发它的唯一属性:单击时onClickSend.无需担心用户,标题或消息.
但是,这种方法有一个很大的缺点:onClickSend的引用会在每次商店更改时发生变化,这会导致在更大的真实案例中表现非常糟糕.
性能问题的解决方案可能是使用redux-thunk并直接在动作中访问状态.
// Action file
var sendMessageAction = createAction("SEND_MESSAGE", function(dispatch, getState) {
// executed by redux thunk
const state = getState();
const args = {
user: selectors.selectedUser(state),
title: selectors.title(state),
message: selectors.message(state),
}
dispatch(sendMessage(args))
})
// Container file
function mapDispatchToProps(dispatch) {
onClickSend: dispatch(sendMessageAction())
}
Run Code Online (Sandbox Code Playgroud)
但我不喜欢这种方法,因为:
我现在已经在一个大型的redux应用程序上工作了一段时间,这是迄今为止我对Redux的最大痛苦.令人惊讶的是,我没有找到太多关于如何解决它的信息,所以我想知道我是否遗漏了一些基本的东西.
你对这个问题有什么看法?
您缺少第四种方法(类似于您的mergeProps选择):让父组件传递一个绑定函数或捕获这些值的回调闭包,例如:
// using bind()
<SendButton onClick={sendMessage.bind(null, user, title, message)}
// or, as an inline arrow function
SendButton onClick={() => this.sendMessage(user, title, message)}
Run Code Online (Sandbox Code Playgroud)
我在理论前提第五方法可能是连接父母的SendButton,有它通过一个非常简单的点击处理程序的按钮,让家长担心从自己的道具(即保持按钮本身完全表象的观点,并将逻辑放在按钮的父级中)。实际上,我想这几乎是@samanime的建议。
您实际使用哪种方法取决于您。我个人可能会倾向于最后一个,只是这样它不会在每次重新渲染时都重新创建一个函数。(特别是,我会避免这种mergeProps方法,因为每次商店更新时,它都会重新创建一个函数,这比重新渲染组件的次数还要多。)
我实际上在我的博客文章Idiomatic Redux:关于Thunk,Sagas,Abstraction和Reusability的思想中解决了有关thunk中的状态访问是否打破“单向数据流”的问题。综上所述,我认为它并没有真正打破单向流,我的观点是,访问thunk中的状态是一种完全有效的方法。
附带说明一下,我通常建议人们使用object速记参数与绑定方法connect,而不是编写实际的mapDispatchToProps函数:
const mapDispatch = {
onClickSend : actions.sendMessage
};
export default connect(mapState, mapDispatch)(MyComponent);
Run Code Online (Sandbox Code Playgroud)
对我来说,几乎没有理由真正写出一个单独的mapDispatch函数(我也在我的文章Idiomatic Redux:为什么使用Action Creators中谈到)。
| 归档时间: |
|
| 查看次数: |
3661 次 |
| 最近记录: |