Redux-Form 初始值来自
Posted
技术标签:
【中文标题】Redux-Form 初始值来自【英文标题】:Redux-Form initial values from 【发布时间】:2017-05-07 03:04:57 【问题描述】:我正在尝试使用来自 API 的数据填写个人资料表单。不幸的是 redux-form 在这种情况下不想与我合作。出于某种原因,无论我做什么,字段都是空的。
出于某种原因,设置固定值而不是从 reducer 传递的值效果很好。
也许这是因为我在动作创建者内部使用 redux-promise 进行 API 调用?我怎样才能忍受它并摆脱它。这是我的表单组件。
import React, Component from 'react';
import reduxForm, Field from 'redux-form';
import connect from 'react-redux';
import fetchRoleList, fetchUserData from '../actions';
class UserEdit extends Component
componentWillMount()
this.props.fetchRoleList();
this.props.fetchUserData();
handleEditProfileFormSubmit(formProps)
console.log(formProps);
getRoleOptions(selected_id)
if (!this.props.profile)
return <option>No data</option>;
return this.props.profile.roles.map(role =>
return <option key=role.role_id value=role.role_id>role.name</option>;
);
renderField(props)
const input, placeholder, label, value, type, meta: touched, error = props;
return (
<fieldset className=`form-group $ (touched && error) ? 'has-error' : '' `>
<label>label</label>
<input className="form-control" ...input type=type placeholder=placeholder />
touched && error && <div className="error">error</div>
</fieldset>
);
renderSelect( input, placeholder, options, label, type, meta: touched, error )
return (
<fieldset className=`form-group $ (touched && error) ? 'has-error' : '' `>
<label>label</label>
<select className="form-control" ...input>
options
</select>
touched && error && <div className="error">error</div>
</fieldset>
);
render()
const handleSubmit = this.props;
const user = this.props.profile.user;
return (
<div> user ? user.email : ''
<form onSubmit=handleSubmit(this.handleEditProfileFormSubmit.bind(this))>
<Field name="email" label="Email:" component=this.renderField type="text" placeholder="email@gmail.com" className="form-control"/>
<Field name="name" label="Name:" component=this.renderField type="text" placeholder="John Doe" className="form-control"/>
<Field name="role" label="Role:" component=this.renderSelect type="select" className="form-control" options=this.getRoleOptions()/>
<button action="submit" className="btn btn-primary">Edit user</button>
<Field name="password" label="Password:" component=this.renderField type="password" className="form-control"/>
<Field name="passwordConfirm" label="Confirm Password:" component=this.renderField type="password" className="form-control"/>
this.props.errorMessage
&& <div className="alert alert-danger">
<strong>Oops!</strong> this.props.errorMessage
</div>
<button action="submit" className="btn btn-primary">Sign up!</button>
</form>
</div>
);
let InitializeFromStateForm = reduxForm(
form: 'initializeFromState'
)(UserEdit);
InitializeFromStateForm = connect(
state => (
profile: state.profile,
initialValues: state.profile.user
),
fetchRoleList, fetchUserData
)(InitializeFromStateForm);
export default InitializeFromStateForm;
我相信动作创建器也会很有用:
export function fetchUserData(user_id)
user_id = user_id ? user_id : '';
const authorization = localStorage.getItem('token');
const request = axios.get(`$ROOT_URL/user/$user_id`,
headers: authorization
);
return
type: FETCH_USER,
payload: request
;
【问题讨论】:
那么问题是尽管您的 initialValues 道具已更改,但您的表单并未填充新数据,对吗? 其实不是。我想最初用减速器的数据填写表格,以后不关心减速器。 【参考方案1】:您需要添加enableReinitialize: true
,如下所示。
let InitializeFromStateForm = reduxForm(
form: 'initializeFromState',
enableReinitialize : true // this is needed!!
)(UserEdit)
如果您的 initialValues 属性得到更新,您的表单也会更新。
【讨论】:
花了 3 个小时搜索。很难找到,但enableReinitialize : true
完成了这项工作。谢谢你。
我什至不会承认我今天为此浪费了多少时间。你真是个英雄!
我花了大约三个小时在这上面。谢谢!
哦,伙计,但是那个文档花了几个小时:(
是的。有用。太奇怪了,官方文档里没找到【参考方案2】:
要设置initialValues
,在redux 的connect()
装饰器之前应用reduxForm()
装饰器很重要。如果装饰器的顺序颠倒,则不会从 store 状态填充字段。
const FormDecoratedComponent = reduxForm(...)(Component)
const ConnectedAndFormDecoratedComponent = connect(...)(FormDecoratedComponent)
如果除了第一次设置值之外,您还需要在每次状态更改时重新填充表单,然后设置enableReinitialize: true
在this answer中找到一个简单的例子。
阅读官方documentation and full example。
阅读此问题here。
【讨论】:
【参考方案3】:所以,你正在尝试:
将 API 数据加载到表单中 在加载时更新表单(又名initialValues
)
虽然@FurkanO 可能会起作用,但我认为最好的方法是在您获得所有异步数据时加载表单,您可以通过创建父组件/容器来做到这一点:
UserEditLoader.jsx
componentDidMount()
// I think this one fits best for your case, otherwise just switch it to
// componentDidUpdate
apiCalls();
/* api methods here */
render()
const profile = this.props;
return (
profile && <UserEdit profile=profile />
);
基本上你应该在UserEditLoader
中做的是执行 API 函数并更新状态(或者如果 redux 连接了 props)。每当 profile 变量不为空(意味着你得到了你期望的数据),然后挂载 UserEdit
并将 profile 作为 prop。
【讨论】:
【参考方案4】:initialize() 是 reduxForm 提供的一个 prop,可以用来填充表单值。
change() 是 reduxFrom 提供的另一个用于更改字段值的 prop。
import * as React from 'react';
import Field, reduxForm from 'redux-form';
import connect from 'react-redux';
import withRouter from 'react-router-dom';
const submit = values =>
// print the form values to the console
console.log(values)
interface Props
history?: any;
location?: any;
session?: any;
handleSubmit?: Function;
initialize?: Function;
change?: Function;
class ContactForm extends React.Component<Props, any>
constructor(props, state)
super(props, state);
this.state =
value: ''
;
componentDidMount()
const initialize, session, location = this.props;
console.log(location.pathname);
if (session && session.user)
const values =
firstName: session.user.name,
lastName: session.user.lastName,
email: session.user.email
;
initialize(values);
componentWillReceiveProps(nextProps)
const initialize, session = this.props;
if (nextProps.session !== session)
if (nextProps.session && nextProps.session.user)
const values =
firstName: nextProps.session.user.name,
lastName: nextProps.session.user.lastName,
email: nextProps.session.user.email
;
initialize(values);
else
const values =
firstName: null,
lastName: null,
email: null
;
initialize(values);
render()
const handleSubmit, change = this.props;
return (
<React.Fragment>
<form onSubmit=handleSubmit(submit)>
<div>
<label htmlFor="firstName">First Name</label>
<Field name="firstName" component="input" type="text" />
</div>
<div>
<label htmlFor="lastName">Last Name</label>
<Field name="lastName" component="input" type="text" />
</div>
<div>
<label htmlFor="email">Email</label>
<Field name="email" component="input" type="email" />
</div>
<button type="submit">Submit</button>
</form>
<input type="text" value=this.state.value
onChange=(e) =>
this.setState( value: e.target.value );
change('firstName', e.target.value);
/>
</React.Fragment>
);
export default connect((state) =>
return
session: state.session
,
)(withRouter((reduxForm(
form: 'contact'
)(ContactForm))));
【讨论】:
【参考方案5】:如果 enableReinitialize : true
技巧不起作用,您可以在 initialValues
属性更改时更新每个字段。
componentWillReceiveProps(nextProps)
const change, initialValues = this.props
const values = nextProps.initialValues;
if(initialValues !== values)
for (var key in values)
if (values.hasOwnProperty(key))
change(key,values[key]);
我从未与FieldsArray
合作过,但我认为这在这里行不通。
【讨论】:
【参考方案6】:对于一个无状态的功能组件,你可以这样做:
componentWillMount()
this.props.initialize( discountCodes: ["ABC200", "XYZ500"] );
对于一个类,你可以这样做:
const mapStateToProps = state => (
initialValues:
discountCodes: ["ABC200", "XYZ500"]
);
【讨论】:
以上是关于Redux-Form 初始值来自的主要内容,如果未能解决你的问题,请参考以下文章
使用material-ui为redux-form设置initialValues无效