Redux 形式的 handleSubmit:如何访问存储状态?
Redux-form handleSubmit: How to access store state?
在 redux 形式的 handleSubmit
函数中,它进行 Ajax 调用,Ajax 中需要来自 Redux 状态的一些属性(例如用户ID).
如果我想在表单的组件中定义 handleSubmit
,这将很容易:只需调用 mapStateToProps
传递我需要的任何内容,然后从我的 this.props
中读取它handleSubmit
.
但是,作为一名优秀的 React-Redux 开发人员,我编写了 单独的视图组件和容器 ,因此我的视图组件可以很简单,几乎没有或没有行为。因此,我想 在我的容器中定义 handleSubmit。
同样,简单 - redux-form 的设置就是为了做到这一点。在mapDispatchToProps
中定义一个onSubmit
,表单会自动调用它。
除了,哦等等,在 mapDispatchToProps
中无法访问 redux 状态。
好的,没问题,我将把我需要的道具连同表单值一起传递到 handleSubmit
。
嗯,等等,使用这种机制不可能将任何数据传递到 handleSubmit
!您获得一个参数 values
,并且无法添加另一个参数。
这留下了以下没有吸引力的替代方案(我可以验证其中 1 和 2 的工作):
1 在表单组件中定义一个提交处理程序, 并从那里调用从 mapDispatchToProps 传入的我自己的自定义提交处理程序函数。这没关系,但需要我的组件从 redux 状态知道一些不需要显示表单的道具。 (这个问题不是 redux-form 独有的。)
dumbSubmit(values)
{
const { mySubmitHandler, user} = this.props;
mySubmitHandler(values, user);
}
<form onSubmit={ handleSubmit(this.dumbSubmit.bind(this)) }>
或者,更简洁地说,这都可以组合成一个箭头函数:
<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props.user);}
然后为了使这个处理程序完全不可知,它可以将整个 this.props 传递回自定义处理程序:
<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props);}
2 在 mergeProps 中定义 onSubmit 而不是 mapDispatchToProps,因此它可以访问 stateProps。 Dan Abramov recommends against using mergeProps (for performance reasons),所以这似乎不是最优的。
function mergeProps(stateProps, dispatchProps, ownProps) {
const { user } = stateProps.authReducer;
const { dispatch } = dispatchProps;
return {
...ownProps,
...dispatchProps,
...stateProps,
onSubmit: (values) => {
const { name, description } = values;
const thing = new Thing(name, description, []);
dispatch(createNewThing(thing, user.id));
}
}
3 将状态属性复制到 redux 表单字段中,这些字段不会映射到表单组件中的任何输入控件。这将确保它们可以在传递回 handleSubmit
的 values
参数中访问。这看起来有点像 hack。
必须有更好的方法!
有没有更好的方法?
在花时间细化这个问题之后,选项 #1 实际上相当不错,在最后的迭代中(将所有道具传递回自定义处理程序的箭头函数)。它允许组件是无状态的,并且完全不知道它不使用的任何状态。所以我会称之为一个合理的答案。我很想听听您更好的解决方案!
在表单组件中使用箭头函数定义提交处理程序,并从那里调用我自己的从 mapDispatchToProps 传入的自定义提交处理程序函数。
<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props.user);}
然后为了让这个处理程序完全不可知,将整个 this.props 传递回自定义处理程序:
<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props);}
如果 Submit 函数只需要不属于表单的值和属性,我们可以只传回表单不使用的那些属性。在无状态组件中,这可能看起来像:
const Thing_Create = ({ fields: {name, description},
error,
handleSubmit,
mySubmitHandler,
submitting,
onCancel,
...otherprops}) => {
return (
<div>
<form onSubmit={ handleSubmit((values)=>{
mySubmitHandler(values, otherprops);}) }>
[rest of form definition would go here]
我可以通过绑定 this
.
来解决这个问题
渲染中的某处()
<MyCustomFormComponent onSubmit={handleSubmit.bind(this)}/>
handleSumit
handleSubmit(fields) {
this.props.onSubmit(fields); //this is properly bound, HURRAY :-)
}
MapDispatchToProps 优秀开发者:-)
const mapDispatchToProps = dispatch => ({
onSubmit: (fields) =>
dispatch({type: auth.actionTypes.LOGIN, payload: auth.api.login(fields)})
});
我找到的最佳方法与您提出的第一个解决方案非常相似。
利用 redux-form 传递的 handleSubmit
prop 可以采用将用作 onSubmit
prop 的函数,并使用部分应用程序传递任何其他参数需要 onSubmit
.
动作创作者:
function updateUser(id, { name, lastname }) { ... }
假设组件得到一个 onUpdateUser
属性,它只是将参数直接传递给动作创建者。并且该组件还获得 user
,一个具有 id
属性 的对象,我们希望将其与字段中的值一起传递给动作创建者。
组件
<form onSubmit={this.props.handleSubmit(this.props.onUpdateUser.bind(null, this.props.user.id))}>
这可以很容易地为无状态功能组件重写,只要您将它们放在 action creator 的左侧,就可以处理任意数量的参数,而且它不需要任何繁重的工作,只是 bind
这是 @stone's 的变体,但您可以通过函数式编程分解选项 1:
const mySubmitHandler = props => values => { /* ...code here */ }
<form onSubmit={ handleSubmit(mySubmitHandler(this.props)) }>
在这种情况下,mySubmitHandler
将 return 一个只接受一个参数的函数,该参数已经关闭了 this.props
,因此无需明确提及 values
handleSubmit
正在传递的论点。
您可以通过 ramda.
以更好、更易读的方式执行 mySubmitHandler
的柯里化
import { curry } from 'ramda';
const mySubmitHandler = curry((props, values) => { /* ...code here */ });
您可以更进一步,组合 handleSubmit
和 mySubmitHandler
import { compose, curry } from 'ramda';
const handleSubmit = values => { /* ...code here */ };
const mySubmitHandler = curry((props, values) => { /* ...code here */ });
const onSubmit = compose(handleSubmit, mySubmitHandler);
<form onSubmit={ onSubmit(this.props) }>
请注意,onSubmit(this.props)
return 是一个接受一个参数 (values
) 并关闭 this.props
的函数,创建一个可以访问所有属性的函数它需要!
在 redux 形式的 handleSubmit
函数中,它进行 Ajax 调用,Ajax 中需要来自 Redux 状态的一些属性(例如用户ID).
如果我想在表单的组件中定义 handleSubmit
,这将很容易:只需调用 mapStateToProps
传递我需要的任何内容,然后从我的 this.props
中读取它handleSubmit
.
但是,作为一名优秀的 React-Redux 开发人员,我编写了 单独的视图组件和容器 ,因此我的视图组件可以很简单,几乎没有或没有行为。因此,我想 在我的容器中定义 handleSubmit。
同样,简单 - redux-form 的设置就是为了做到这一点。在mapDispatchToProps
中定义一个onSubmit
,表单会自动调用它。
除了,哦等等,在 mapDispatchToProps
中无法访问 redux 状态。
好的,没问题,我将把我需要的道具连同表单值一起传递到 handleSubmit
。
嗯,等等,使用这种机制不可能将任何数据传递到 handleSubmit
!您获得一个参数 values
,并且无法添加另一个参数。
这留下了以下没有吸引力的替代方案(我可以验证其中 1 和 2 的工作):
1 在表单组件中定义一个提交处理程序, 并从那里调用从 mapDispatchToProps 传入的我自己的自定义提交处理程序函数。这没关系,但需要我的组件从 redux 状态知道一些不需要显示表单的道具。 (这个问题不是 redux-form 独有的。)
dumbSubmit(values)
{
const { mySubmitHandler, user} = this.props;
mySubmitHandler(values, user);
}
<form onSubmit={ handleSubmit(this.dumbSubmit.bind(this)) }>
或者,更简洁地说,这都可以组合成一个箭头函数:
<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props.user);}
然后为了使这个处理程序完全不可知,它可以将整个 this.props 传递回自定义处理程序:
<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props);}
2 在 mergeProps 中定义 onSubmit 而不是 mapDispatchToProps,因此它可以访问 stateProps。 Dan Abramov recommends against using mergeProps (for performance reasons),所以这似乎不是最优的。
function mergeProps(stateProps, dispatchProps, ownProps) {
const { user } = stateProps.authReducer;
const { dispatch } = dispatchProps;
return {
...ownProps,
...dispatchProps,
...stateProps,
onSubmit: (values) => {
const { name, description } = values;
const thing = new Thing(name, description, []);
dispatch(createNewThing(thing, user.id));
}
}
3 将状态属性复制到 redux 表单字段中,这些字段不会映射到表单组件中的任何输入控件。这将确保它们可以在传递回 handleSubmit
的 values
参数中访问。这看起来有点像 hack。
必须有更好的方法!
有没有更好的方法?
在花时间细化这个问题之后,选项 #1 实际上相当不错,在最后的迭代中(将所有道具传递回自定义处理程序的箭头函数)。它允许组件是无状态的,并且完全不知道它不使用的任何状态。所以我会称之为一个合理的答案。我很想听听您更好的解决方案!
在表单组件中使用箭头函数定义提交处理程序,并从那里调用我自己的从 mapDispatchToProps 传入的自定义提交处理程序函数。
<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props.user);}
然后为了让这个处理程序完全不可知,将整个 this.props 传递回自定义处理程序:
<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props);}
如果 Submit 函数只需要不属于表单的值和属性,我们可以只传回表单不使用的那些属性。在无状态组件中,这可能看起来像:
const Thing_Create = ({ fields: {name, description},
error,
handleSubmit,
mySubmitHandler,
submitting,
onCancel,
...otherprops}) => {
return (
<div>
<form onSubmit={ handleSubmit((values)=>{
mySubmitHandler(values, otherprops);}) }>
[rest of form definition would go here]
我可以通过绑定 this
.
渲染中的某处()
<MyCustomFormComponent onSubmit={handleSubmit.bind(this)}/>
handleSumit
handleSubmit(fields) {
this.props.onSubmit(fields); //this is properly bound, HURRAY :-)
}
MapDispatchToProps 优秀开发者:-)
const mapDispatchToProps = dispatch => ({
onSubmit: (fields) =>
dispatch({type: auth.actionTypes.LOGIN, payload: auth.api.login(fields)})
});
我找到的最佳方法与您提出的第一个解决方案非常相似。
利用 redux-form 传递的 handleSubmit
prop 可以采用将用作 onSubmit
prop 的函数,并使用部分应用程序传递任何其他参数需要 onSubmit
.
动作创作者:
function updateUser(id, { name, lastname }) { ... }
假设组件得到一个 onUpdateUser
属性,它只是将参数直接传递给动作创建者。并且该组件还获得 user
,一个具有 id
属性 的对象,我们希望将其与字段中的值一起传递给动作创建者。
组件
<form onSubmit={this.props.handleSubmit(this.props.onUpdateUser.bind(null, this.props.user.id))}>
这可以很容易地为无状态功能组件重写,只要您将它们放在 action creator 的左侧,就可以处理任意数量的参数,而且它不需要任何繁重的工作,只是 bind
这是 @stone's
const mySubmitHandler = props => values => { /* ...code here */ }
<form onSubmit={ handleSubmit(mySubmitHandler(this.props)) }>
在这种情况下,mySubmitHandler
将 return 一个只接受一个参数的函数,该参数已经关闭了 this.props
,因此无需明确提及 values
handleSubmit
正在传递的论点。
您可以通过 ramda.
以更好、更易读的方式执行mySubmitHandler
的柯里化
import { curry } from 'ramda';
const mySubmitHandler = curry((props, values) => { /* ...code here */ });
您可以更进一步,组合 handleSubmit
和 mySubmitHandler
import { compose, curry } from 'ramda';
const handleSubmit = values => { /* ...code here */ };
const mySubmitHandler = curry((props, values) => { /* ...code here */ });
const onSubmit = compose(handleSubmit, mySubmitHandler);
<form onSubmit={ onSubmit(this.props) }>
请注意,onSubmit(this.props)
return 是一个接受一个参数 (values
) 并关闭 this.props
的函数,创建一个可以访问所有属性的函数它需要!