如何在`redux-form`中将道具传递给装饰形式?

时间:2017-06-27 08:38:50

标签: javascript forms reactjs redux redux-form

我正在使用redux-form构建一个向导表单,并遇到一个问题,即onClick处理程序没有作为支持从容器组件传递到表单中。

我在过去几个小时内搜索过的文档都没有用...似乎有办法将道具传递给装饰好的HOC,但我看不到任何这样的例子。

以下是相关代码:

RadioButtons.js(调用onClick函数的地方)

const RadioButtons = props => {
  const { question, handleClick } = props;
  const radioClassNames = classNames({
    "radio-button": true,
    "radio-button-image-wrapper": question.image,
    "radio-button-text-wrapper": !question.image,
  });
  return (
    <div className="radio-buttons">
      <div className="radio-buttons-wrapper">
        {question.options.map((option, index) => (
          <div className={radioClassNames} key={index} onClick={handleClick}>
            <Field
              component="input"
              type="radio"
              name={`option-${option}`}
              id={`option-${option}`}
            />
            <label className="radio-button-text" htmlFor={option}>
              {option}
            </label>
        )}
          </div>
        )
        )}
      </div>
    </div>
  )
}

RadioButtons.PropTypes = {
  question: PropTypes.object.isRequired,
  handleClick: PropTypes.func,
}

export default RadioButtons;

当我在React DevTools中检查这个组件时,它没有这个支柱。它也不属于以下组成部分......

Question.js(这决定了要渲染的问题类型;滑块,单选按钮,文本/电子邮件/电话输入等)

const Question = props => {
  const { handleSubmit, onBlur, question, handleClick } = props;
  return (
    <div className={`question question-${question.name}`}>
      <form className={props.className} onSubmit={handleSubmit}>
        <div className="question-wrapper">
          <label className={`question-label-${question.name}`}>{question.text}</label>
          { question.image === true && question.type !== "checkbox" && question.type !== "radio" &&
            <img className="question-image" src={`/images/${question.name}.png`} />
          }
          { question.type === "radio" && <RadioButtons question={question} handleClick={handleClick} /> }
          { question.type === "range" && <Slider question={question} /> }
          { question.type !== "checkbox" && question.type !== "radio" && question.type !== "range" &&
            <Field
              component={question.component}
              type={question.type}
              name={question.name}
              placeholder={question.placeholder}
              onBlur={onBlur}
            />
          }
        </div>
      </form>
    </div>
  )
}

Question.PropTypes = {
  handleSubmit: PropTypes.func,
  onBlur: PropTypes.func,
  question: PropTypes.object.isRequired,
  handleClick: PropTypes.func,
}

export default reduxForm({
  form: 'quiz',
  destroyOnUnmount: false,
  forceUnregisterOnUnmount: true,
})(Question);

QuestionContainer.jsQuestion.js的包装器;确定是在屏幕上呈现多个问题还是只呈现一个问题)。 handleClick道具最终会显示在这里!

const QuestionContainer = props => {
  const { question, handleClick } = props;

  const questionClassNames = classNames({
    'question-wrapper': true,
    'question-single': props.question !== 'combined',
    'question-multiple': props.question === 'combined',
  });

  const renderQuestions = question => {
    if (question.component === 'combined') {
      return (
       <div className="multi-question-container">
         <label className="multi-question-label">{question.text}</label>
         <div className="multi-question-wrapper">
           {question.subQuestions.map((subQuestion, index) => {
             const newName = `${question.name}-${subQuestion.name}`;
             const newSubQuestion = Object.assign({}, subQuestion, { name: newName })
             return (
               <Question
                 question={newSubQuestion}
                 key={index}
                 className={questionClassNames}
                 handleClick={handleClick}
               />
             )
           })}
         </div>
       </div>
      )} else {
       return (
         <Question
           question={question}
           className={questionClassNames}
         />
       )
     }
  }

  return (
    <div className="question-container">
      {renderQuestions(question)}
    </div>
  )
}

QuestionContainer.PropTypes = {
  question: PropTypes.object.isRequired,
  handleClick: PropTypes.func,
}

export default QuestionContainer;

但是...... handleClick道具Quiz组件中没有显示,我实际上需要用它来调用{{1 }}:

nextScreen()

class Quiz extends Component { constructor(props) { super(props); this.state = { screen: 0 } } nextScreen = () => { console.log("nextScreen"); if (this.state.screen < data.questions.length) { this.setState({screen: this.state.screen + 1}); } else { this.props.calculateResult(this.props.form.quiz.values); this.props.history.push('/congratulations'); } } lastScreen = () => { if (this.state.screen > 1) { this.setState({screen: this.state.screen - 1}); } else { this.props.history.push('/'); } } render() { const currentQuestion = Object.assign({}, data.questions[this.state.screen]); let arrowSource = `/images/arrow-button-${arrowColor}.png`; return ( <div> <div className="quiz-wrapper"> <ArrowButton src={arrowSource} route="back" handleClick={this.lastScreen} /> <div className="quiz-wrapper-inner"> <QuestionContainer question={currentQuestion} handleClick={this.nextScreen} /> </div> <ArrowButton src={arrowSource} route="forward" handleClick={this.nextScreen} /> </div> </div> ) } } const mapStateToProps = state => { return { form: state.form, } }; const mapDispatchToProps = dispatch => { return { calculateResult: answers => dispatch(calculateResult(answers)), } }; export default connect(mapStateToProps, mapDispatchToProps)(Quiz); 组件上的handleClick道具工作正常,可以毫不费力地调用ArrowButton / nextScreen()。只有lastScreen()才能传递它。

1 个答案:

答案 0 :(得分:2)

Questions组件中有两个QuestionsContainer组件实例。当满足question.component === 'combined'条件时,您传递的是handleClick道具,而则不是,因此您的Questions组件中无法使用它。

您还需要在else条件中将handleClick作为道具传递

const renderQuestions = question => {
    if (question.component === 'combined') {
      return (
       <div className="multi-question-container">
         <label className="multi-question-label">{question.text}</label>
         <div className="multi-question-wrapper">
           {question.subQuestions.map((subQuestion, index) => {
             const newName = `${question.name}-${subQuestion.name}`;
             const newSubQuestion = Object.assign({}, subQuestion, { name: newName })
             return (
               <Question
                 question={newSubQuestion}
                 key={index}
                 className={questionClassNames}
                 handleClick={handleClick}
               />
             )
           })}
         </div>
       </div>
      )} else {
       return (
         <Question
           question={question}
           className={questionClassNames}
           handleClick={handleClick}
         />
       )
     }
  }