所以我有这个组件。它接收道具并在componentWillReceiveProps
我将这些道具设置为状态以填写一些表格细节。当我手动输入这样的网址http://localhost:3000/dashboard/emailpreview/SKXj7t86agAzmRefG
时它会起作用
它很棒!但是,如果我单击指向该URL的react-router的链接,则根本不会触发componentWillReceiveProps,因此我的表单字段不会预填充。但是,如果我执行手动刷新,一切都会有效。为什么会这样?有什么问题?为什么componentWillReceiveProps
未在Link
上触发?
import React, { Component } from 'react'
import { browserHistory } from 'react-router'
import { Editor } from 'react-draft-wysiwyg'
import { convertToRaw } from 'draft-js'
import { createContainer } from 'meteor/react-meteor-data'
import { Emails } from '../../../../../imports/collections/emails/Emails'
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'
import draftToHtml from 'draftjs-to-html'
import { stateFromHTML } from 'draft-js-import-html'
import _ from 'lodash'
class EmailEditor extends Component {
constructor (props) {
super(props)
this.state = {
name: '',
to: '',
subject: '',
html: '',
error: ''
}
}
// TODO: If there is id then fill in the information
// TODO: Subscribe and find and fill in with state
componentWillReceiveProps (nextProps) {
console.log('acsdcdsc', nextProps.email.name)
this.setState({name: nextProps.email.name, to: nextProps.email.to, subject: nextProps.email.subject})
}
handleChange (event) {
const changedOne = event.target.name
const newValue = event.target.value
const newState = {}
newState[changedOne] = newValue
this.setState(newState)
}
saveEmail () {
const self = this
console.log('saveEmail')
const { emailId } = this.props.params
console.log(emailId)
console.log('email')
const { name, to, subject, attachments, editorState } = this.state
console.log('editorState', editorState)
if (_.isEmpty(editorState)) {
self.setState({error: 'Please fill requaired fields'})
return
}
const rawContentState = convertToRaw(editorState.getCurrentContent())
const html = draftToHtml(rawContentState)
console.log('html', html)
const email = {
emailId,
name,
to,
subject,
html,
attachments // TODO: figure out how to send this
}
if (emailId === 'new') {
Meteor.call('emails.insert', email, (err, emailId) => {
if (err) {
self.setState({error: 'Please fill requaired fields'})
return
}
if (emailId) console.log(emailId)
browserHistory.push(`/dashboard/emailpreview/${emailId}`)
})
} else {
Meteor.call('emails.update', email, (err, emailId) => {
if (err) console.log(err)
if (emailId) console.log(emailId)
browserHistory.push(`/dashboard/emailpreview/${emailId}`)
})
}
}
renderEditor () {
return(
<div className="form-group">
<div><label style={{display: 'block', color: 'red', marginBottom: '10px'}}>*</label><input value={this.state.name} onChange={this.handleChange.bind(this)} type="text" name="name" placeholder="Email Name" /></div>
<div><label style={{display: 'block', color: 'red', marginBottom: '10px'}}>*</label><input value={this.state.to} onChange={this.handleChange.bind(this)} type="text" name="to" placeholder="To" /></div>
<div><label style={{display: 'block', color: 'red', marginBottom: '10px'}}>*</label><input value={this.state.subject} onChange={this.handleChange.bind(this)} type="text" name="subject" placeholder="Subject" /></div>
<div><span style={{display: 'block', color: 'red', margin: '10px'}}>{this.state.error}</span></div>
<Editor
toolbarClassName="wysiwig-toolbar"
wrapperClassName="wysiwig-wrapper"
editorClassName="wysiwig-editor"
onEditorStateChange={(editorState) => {
this.setState({
editorState
})
console.log(editorState)
}}
/>
<button onClick={this.saveEmail.bind(this)} className="btn btn-success">Save</button>
<button className="btn btn-primary">Send</button>
<button className="btn btn-primary">Test</button>
</div>
)
}
render () {
console.log('listItems1010', this.state)
console.log('listItems prop11010', this.props.email)
return (
<div className="EmailEditor">
{this.renderEditor()}
</div>
)
}
}
// https://jpuri.github.io/react-draft-wysiwyg/#/docs?_k=jjqinp
// {/* editorState={editorState}
// toolbarClassName="home-toolbar"
// wrapperClassName="home-wrapper"
// editorClassName="home-editor"
// onEditorStateChange={this.onEditorStateChange}
// uploadCallback={uploadImageCallBack} */}
export default createContainer((props) => {
const {emailId} = props.params
Meteor.subscribe('emails')
return {email: Emails.findOne(emailId)}
}, EmailEditor)
答案 0 :(得分:1)
事实证明,在初始渲染过程中未触发componentWillReceiveProps
。它仅在组件更新时触发。因此,对于setState
初始渲染,我使用componentDidMount
就像这样
componentDidMount () {
if (this.props.email) {
this.setState({
name: this.props.email.name,
to: this.props.email.to,
subject: this.props.email.subject,
html: this.props.email.html,
editorState: EditorState.createWithContent(stateFromHTML(this.props.email.html))
})
}
}
所以最终的代码看起来像是
import React, { Component } from 'react'
import { browserHistory } from 'react-router'
import { Editor } from 'react-draft-wysiwyg'
import { convertToRaw, EditorState } from 'draft-js'
import { createContainer } from 'meteor/react-meteor-data'
import { Emails } from '../../../../../imports/collections/emails/Emails'
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'
import draftToHtml from 'draftjs-to-html'
import { stateFromHTML } from 'draft-js-import-html'
import _ from 'lodash'
class EmailEditor extends Component {
constructor (props) {
super(props)
this.state = {
name: '',
to: '',
subject: '',
html: '',
error: '',
editorState: EditorState.createEmpty()
}
}
componentWillReceiveProps (nextProps, nextContext) {
console.log('componentWillReceiveProps nextProps.email.name', nextProps.email.name)
this.setState({
name: nextProps.email.name,
to: nextProps.email.to,
subject: nextProps.email.subject,
html: nextProps.email.html,
editorState: EditorState.createWithContent(stateFromHTML(nextProps.email.html))
})
}
componentDidMount () {
if (this.props.email) {
this.setState({
name: this.props.email.name,
to: this.props.email.to,
subject: this.props.email.subject,
html: this.props.email.html,
editorState: EditorState.createWithContent(stateFromHTML(this.props.email.html))
})
}
}
handleChange (event) {
const changedOne = event.target.name
const newValue = event.target.value
const newState = {}
newState[changedOne] = newValue
this.setState(newState)
}
saveEmail () {
const self = this
console.log('saveEmail')
const { emailId } = this.props.params
console.log(emailId)
console.log('email')
const { name, to, subject, attachments, editorState } = this.state
console.log('editorState', editorState)
if (_.isEmpty(editorState)) {
self.setState({error: 'Please fill requaired fields'})
return
}
const rawContentState = convertToRaw(editorState.getCurrentContent())
const html = draftToHtml(rawContentState)
console.log('html', html)
const email = {
emailId,
name,
to,
subject,
html,
attachments // TODO: figure out how to send this
}
if (emailId === 'new') {
Meteor.call('emails.insert', email, (err, emailId) => {
if (err) {
self.setState({error: 'Please fill requaired fields'})
return
}
if (emailId) console.log(emailId)
browserHistory.push(`/dashboard/emailpreview/${emailId}`)
})
} else {
Meteor.call('emails.update', email, (err, result) => {
if (err) console.log(err)
if (result) console.log('update result', result)
browserHistory.push(`/dashboard/emailpreview/${emailId}`)
})
}
}
renderEditor () {
return (
<div className="form-group">
<div><label style={{display: 'block', color: 'red', marginBottom: '10px'}}>*</label><input
value={this.state.name}
onChange={this.handleChange.bind(this)}
type="text"
name="name"
placeholder="Email Name" /></div>
<div><label style={{display: 'block', color: 'red', marginBottom: '10px'}}>*</label><input
value={this.state.to}
onChange={this.handleChange.bind(this)}
type="text"
name="to"
placeholder="To" /></div>
<div><label style={{display: 'block', color: 'red', marginBottom: '10px'}}>*</label><input
value={this.state.subject}
onChange={this.handleChange.bind(this)}
type="text"
name="subject"
placeholder="Subject" /></div>
<div><span style={{display: 'block', color: 'red', margin: '10px'}}>{this.state.error}</span></div>
<Editor
editorState={this.state.editorState}
toolbarClassName="wysiwig-toolbar"
wrapperClassName="wysiwig-wrapper"
editorClassName="wysiwig-editor"
onEditorStateChange={(editorState) => {
this.setState({
editorState
})
console.log('editorState', editorState)
console.log('this.state', this.state)
}}
/>
<button onClick={this.saveEmail.bind(this)} className="btn btn-success">Save</button>
<button className="btn btn-primary">Send</button>
<button className="btn btn-primary">Test</button>
</div>
)
}
render () {
console.log('render state', this.state)
console.log('render props email', this.props.email)
return (
<div className="EmailEditor">
{this.renderEditor()}
</div>
)
}
}
// https://jpuri.github.io/react-draft-wysiwyg/#/docs?_k=jjqinp
// {/* editorState={editorState}
// toolbarClassName="home-toolbar"
// wrapperClassName="home-wrapper"
// editorClassName="home-editor"
// onEditorStateChange={this.onEditorStateChange}
// uploadCallback={uploadImageCallBack} */}
export default createContainer((props) => {
const {emailId} = props.params
Meteor.subscribe('emails')
return {email: Emails.findOne(emailId)}
}, EmailEditor)
答案 1 :(得分:0)
问题是没有为初始渲染调用componentWillReceiveProps。阅读有关生命周期方法的文档,以便全面了解http://reactjs.cn/react/docs/component-specs.html#lifecycle-methods
您只需在构造函数中设置状态即可解决问题。
constructor (props) {
super(props)
this.state = {
name: props.name,
to: props.email.to,
subject: props.email.subject,
html: '',
error: ''
}
}
该代码可能会产生一些未定义的错误,更完整的解决方案可以避免未定义的错误,类似于:
constructor (props) {
super(props)
const { email, name } = props;
this.state = {
name,
to: email && email.to,
subject: email && email.subject,
html: '',
error: ''
}
}