在react-router Link

时间:2017-01-31 11:55:03

标签: reactjs meteor react-router

所以我有这个组件。它接收道具并在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)

2 个答案:

答案 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: ''
  }
}