使用 Reactjs DatePicker 更新状态不起作用
Update state with Reactjs DatePicker doesn't work
我使用日期选择器添加项目并且它有效,但是当我尝试edit/update那些使用日期选择器的项目时,不起作用!给我很多错误,例如:
失败的道具类型:提供给 DatePicker
的 string
类型的道具 selected
无效,预期 object
组件正在将不受控制的文本类型输入更改为受控制。输入元素不应从不受控制切换到受控(反之亦然)。在组件的生命周期内决定使用受控或非受控输入元素。
失败的道具类型:提供给 Calendar/Month/Week/Day
的 string
类型的道具 selected
无效,应为 object
.
未捕获类型错误:无法读取未定义的 属性'value'
并且输入为空,没有像预期的那样显示今天的日期,示例如下:
这是我的 EditProject 组件:
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
import DatePicker from 'react-datepicker';
import moment from 'moment';
import './EditProject.css';
import 'react-datepicker/dist/react-datepicker.css';
class EditProject extends Component {
constructor(props) {
super(props);
this.state = {
project: {}
}
}
componentDidMount() {
// console.log('PROPS ' + JSON.stringify(this.props));
const { match: { params } } = this.props;
fetch(`/dashboard/project/${params.id}/edit`)
.then(response => {
return response.json()
}).then(project => {
this.setState({
projectname: project.projectname,
typeofproject: project.typeofproject,
imageURL: project.imageURL,
startDate: project.startDate,
endDate: project.endDate
})
})
}
render() {
const { match: { params } } = this.props;
return (
<div className='EditProject'>
<h1 className='EditProject__title'>Edit</h1><h1 className='EditProject__projectname'>{this.state.projectname}</h1>
<hr />
<form method='POST' action={`/dashboard/project/${params.id}/edit?_method=PUT`}>
<div className='form-group container'>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text" style={{border:'none'}} id="basic-addon1">Project Name</span>
</div>
<input type='text' className='form-control input' placeholder='insert new project name' value={this.state.projectname} name='projectname' ref='projectname' onChange={(event) => this.setState({ projectname: event.target.value })} />
</div>
</div>
<div className='form-group container'>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text" style={{border:'none'}} id="basic-addon1">Type of Production</span>
</div>
<select className='form-control input' value={this.state.typeofproject} name='typeofproject' ref='typeofproject' onChange={(event) => this.setState({ typeofproject: event.target.value })}>
<option value='Film (Cinema)'>Film (Cinema)</option>
<option value='Film (TV)'>Film (TV)</option>
<option value='Film (series)'>Film (series)</option>
<option value='Short film'>Short film</option>
<option value='TV mini-series'>TV mini-series</option>
<option value='TV series'>TV series</option>
<option value='TV program'>TV program</option>
<option value='TV reporting'>TV reporting</option>
<option value='Vox Pop'>Vox Pop</option>
<option value='Advertisement Ad'>Advertisement Ad</option>
<option value='Documentary'>Documentary</option>
<option value='Documentary (TV)'>Documentary (TV)</option>
<option value='Documentary (series)'>Documentary (series)</option>
<option value='Commercial'>Commercial</option>
<option value='Video Clip'>Video Clip</option>
<option value='Live Video Clip TV'>Live Video Clip TV</option>
<option value='Photography Session'>Photography Session</option>
</select>
</div>
</div>
<div className='form-group container'>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text" style={{border:'none'}} id="basic-addon1">Start Date</span>
</div>
// ================DATEPICKER HERE================
<DatePicker
todayButton={"Today"}
dateFormat="DD/MM/YYYY"
selected={this.state.startDate}
value={this.state.startDate}
onChange={(event) => this.setState({ startDate: event.target.value })}
/>
</div>
</div>
<div className='form-group container'>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text" style={{border:'none'}} id="basic-addon1">End Date</span>
</div>
<DatePicker
todayButton={"Today"}
dateFormat="DD/MM/YYYY"
selected={this.state.endDate}
value={this.state.endDate}
onChange={(event) => this.setState({ endDate: event.target.value })}
/>
</div>
</div>
// / ================DATEPICKER HERE================
<div className='form-group container'>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text" style={{border:'none'}} id="basic-addon1">Project Image URL</span>
</div>
<input type='text' className='form-control input 'placeholder='insert new project image URL' value={this.state.imageURL} name='imageURL' ref='imageURL' onChange={(event) => this.setState({ imageURL: event.target.value })} />
</div>
</div>
<div className='form-group container'>
<button type='submit' className='btn btn-default button--update'>Update</button>
<NavLink to={`/project/${params.id}/`} ><button type='submit' style={{ backgroundColor: '#b5b5b5' }} className='btn btn-default button--update'>Cancel</button></NavLink>
</div>
</form>
</div>
);
}
}
export default EditProject;
非常感谢您的帮助!
startDate 不是设置为字符串吗?正如错误所说,我认为它应该是一个 Date 对象。
另一个问题似乎是当你渲染时,你的 fetch 和 setState(在 componentDidMount 中)没有完成。
尝试添加一个状态变量(例如 isLoading),初始化为 true,并在完成所有 componentDidMount 行后将其设置为 false。现在在渲染中检查它,并在 isLoading 为 false 时显示 "loading" 消息。
你还需要注意fetch失败的情况。在这种情况下,您根本无法呈现您的 datePicker。顺便说一句,我不确定 fetch 是否足够好。它在某些错误处理情况下存在问题。我总是使用 axios。
来自您的提取的日期需要转换为 Moment 日期。我不知道你的日期返回的格式是什么,但如果它不是 ISO 8601 格式(YYYY-MM-DD),那么你还需要在创建 Moment 对象时指定格式,所以将你的代码更改为以下之一以下:
startDate: moment(project.startDate)
startDate: moment(project.startDate, 'DD-MM-YYYY') //specify format that is relevant for your date string if it is not ISO8601
组件提供的 onChange 事件处理程序 returns 选定的日期(它不像 普通的 JS 事件处理程序)。因此,您不会收到具有 event.target.value 的对象。相反,您将收到所选日期,因此只需将参数的值设置为状态对象中的 startDate:
onChange={(newDate) => this.setState({ startDate: newDate })}
请注意,该值已经是时刻日期,因此不需要转换。
然后您需要对 endDate 和 endDate 日期选择器执行同样的操作。
另请注意,除非您需要更改输入元素中实际显示的内容,否则并非真的有必要设置值 属性 - 通常您只需使用选定的和日期格式即可获得正确的输出 属性(并且当然将 value 和 selected 设置为相同的东西会导致错误,因为前者需要一个字符串而后者需要一个 moment 对象)。
有关受控到不受控的错误可能是由于您没有在构造函数中完全初始化您的状态 - 您应该在构造函数中将所有组件道具初始化为合理的东西,因为对提取的响应几乎肯定会在之后发生基于承诺的初始渲染。您在构造函数中的初始状态应如下所示(顺便说一下,项目 属性 似乎没有必要):
this.state = {
projectname: '',
typeofproject: 'Film (Cinema)', //if you want a default selected otherwise leave as empty string
imageURL: '',
startDate: moment(),
endDate: moment()
}
我使用日期选择器添加项目并且它有效,但是当我尝试edit/update那些使用日期选择器的项目时,不起作用!给我很多错误,例如:
失败的道具类型:提供给
DatePicker
的string
类型的道具selected
无效,预期object
组件正在将不受控制的文本类型输入更改为受控制。输入元素不应从不受控制切换到受控(反之亦然)。在组件的生命周期内决定使用受控或非受控输入元素。
失败的道具类型:提供给
Calendar/Month/Week/Day
的string
类型的道具selected
无效,应为object
.未捕获类型错误:无法读取未定义的 属性'value'
并且输入为空,没有像预期的那样显示今天的日期,示例如下:
这是我的 EditProject 组件:
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
import DatePicker from 'react-datepicker';
import moment from 'moment';
import './EditProject.css';
import 'react-datepicker/dist/react-datepicker.css';
class EditProject extends Component {
constructor(props) {
super(props);
this.state = {
project: {}
}
}
componentDidMount() {
// console.log('PROPS ' + JSON.stringify(this.props));
const { match: { params } } = this.props;
fetch(`/dashboard/project/${params.id}/edit`)
.then(response => {
return response.json()
}).then(project => {
this.setState({
projectname: project.projectname,
typeofproject: project.typeofproject,
imageURL: project.imageURL,
startDate: project.startDate,
endDate: project.endDate
})
})
}
render() {
const { match: { params } } = this.props;
return (
<div className='EditProject'>
<h1 className='EditProject__title'>Edit</h1><h1 className='EditProject__projectname'>{this.state.projectname}</h1>
<hr />
<form method='POST' action={`/dashboard/project/${params.id}/edit?_method=PUT`}>
<div className='form-group container'>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text" style={{border:'none'}} id="basic-addon1">Project Name</span>
</div>
<input type='text' className='form-control input' placeholder='insert new project name' value={this.state.projectname} name='projectname' ref='projectname' onChange={(event) => this.setState({ projectname: event.target.value })} />
</div>
</div>
<div className='form-group container'>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text" style={{border:'none'}} id="basic-addon1">Type of Production</span>
</div>
<select className='form-control input' value={this.state.typeofproject} name='typeofproject' ref='typeofproject' onChange={(event) => this.setState({ typeofproject: event.target.value })}>
<option value='Film (Cinema)'>Film (Cinema)</option>
<option value='Film (TV)'>Film (TV)</option>
<option value='Film (series)'>Film (series)</option>
<option value='Short film'>Short film</option>
<option value='TV mini-series'>TV mini-series</option>
<option value='TV series'>TV series</option>
<option value='TV program'>TV program</option>
<option value='TV reporting'>TV reporting</option>
<option value='Vox Pop'>Vox Pop</option>
<option value='Advertisement Ad'>Advertisement Ad</option>
<option value='Documentary'>Documentary</option>
<option value='Documentary (TV)'>Documentary (TV)</option>
<option value='Documentary (series)'>Documentary (series)</option>
<option value='Commercial'>Commercial</option>
<option value='Video Clip'>Video Clip</option>
<option value='Live Video Clip TV'>Live Video Clip TV</option>
<option value='Photography Session'>Photography Session</option>
</select>
</div>
</div>
<div className='form-group container'>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text" style={{border:'none'}} id="basic-addon1">Start Date</span>
</div>
// ================DATEPICKER HERE================
<DatePicker
todayButton={"Today"}
dateFormat="DD/MM/YYYY"
selected={this.state.startDate}
value={this.state.startDate}
onChange={(event) => this.setState({ startDate: event.target.value })}
/>
</div>
</div>
<div className='form-group container'>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text" style={{border:'none'}} id="basic-addon1">End Date</span>
</div>
<DatePicker
todayButton={"Today"}
dateFormat="DD/MM/YYYY"
selected={this.state.endDate}
value={this.state.endDate}
onChange={(event) => this.setState({ endDate: event.target.value })}
/>
</div>
</div>
// / ================DATEPICKER HERE================
<div className='form-group container'>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text" style={{border:'none'}} id="basic-addon1">Project Image URL</span>
</div>
<input type='text' className='form-control input 'placeholder='insert new project image URL' value={this.state.imageURL} name='imageURL' ref='imageURL' onChange={(event) => this.setState({ imageURL: event.target.value })} />
</div>
</div>
<div className='form-group container'>
<button type='submit' className='btn btn-default button--update'>Update</button>
<NavLink to={`/project/${params.id}/`} ><button type='submit' style={{ backgroundColor: '#b5b5b5' }} className='btn btn-default button--update'>Cancel</button></NavLink>
</div>
</form>
</div>
);
}
}
export default EditProject;
非常感谢您的帮助!
startDate 不是设置为字符串吗?正如错误所说,我认为它应该是一个 Date 对象。
另一个问题似乎是当你渲染时,你的 fetch 和 setState(在 componentDidMount 中)没有完成。
尝试添加一个状态变量(例如 isLoading),初始化为 true,并在完成所有 componentDidMount 行后将其设置为 false。现在在渲染中检查它,并在 isLoading 为 false 时显示 "loading" 消息。
你还需要注意fetch失败的情况。在这种情况下,您根本无法呈现您的 datePicker。顺便说一句,我不确定 fetch 是否足够好。它在某些错误处理情况下存在问题。我总是使用 axios。
来自您的提取的日期需要转换为 Moment 日期。我不知道你的日期返回的格式是什么,但如果它不是 ISO 8601 格式(YYYY-MM-DD),那么你还需要在创建 Moment 对象时指定格式,所以将你的代码更改为以下之一以下:
startDate: moment(project.startDate)
startDate: moment(project.startDate, 'DD-MM-YYYY') //specify format that is relevant for your date string if it is not ISO8601
组件提供的 onChange 事件处理程序 returns 选定的日期(它不像 普通的 JS 事件处理程序)。因此,您不会收到具有 event.target.value 的对象。相反,您将收到所选日期,因此只需将参数的值设置为状态对象中的 startDate:
onChange={(newDate) => this.setState({ startDate: newDate })}
请注意,该值已经是时刻日期,因此不需要转换。
然后您需要对 endDate 和 endDate 日期选择器执行同样的操作。
另请注意,除非您需要更改输入元素中实际显示的内容,否则并非真的有必要设置值 属性 - 通常您只需使用选定的和日期格式即可获得正确的输出 属性(并且当然将 value 和 selected 设置为相同的东西会导致错误,因为前者需要一个字符串而后者需要一个 moment 对象)。
有关受控到不受控的错误可能是由于您没有在构造函数中完全初始化您的状态 - 您应该在构造函数中将所有组件道具初始化为合理的东西,因为对提取的响应几乎肯定会在之后发生基于承诺的初始渲染。您在构造函数中的初始状态应如下所示(顺便说一下,项目 属性 似乎没有必要):
this.state = {
projectname: '',
typeofproject: 'Film (Cinema)', //if you want a default selected otherwise leave as empty string
imageURL: '',
startDate: moment(),
endDate: moment()
}