从表单构建器

时间:2017-07-10 00:39:32

标签: javascript forms reactjs state persistent-storage

我需要帮助解决从深层嵌套的子/孙子中更新父状态的最佳方法。

我正在使用React创建表单构建器,允许用户通过在localeStorage中保存持久状态来创建,预览和导出表单。表单有问题,每个问题都有可能的子问题。

我的想法是在应用层上保持所有问题的状态,分配localStorage.setItem('questions',this.state.questions)

数据结构如下:

     [
      { question='question 1', 
        type='text', 
        condition=null, 
        isSub= false, 
        subQ=[{
            question='sub question 1',
            ...
            isSub=true,
            subQ=[]
          }]
        },
        {
          question='question 1', 
          ...
          isSub= false, 
          subQ=[]
        },
        question='question 1', 
        ...
        isSub= false, 
        subQ=[]
      }
    ]

我的组件层次结构是App - > QuestionForm - >题。 App保持所有问题的状态,Question管理自己的onChange调用updateInputValue,更新值然后调用绑定到QuestionForm组件的updateParent(key,update)。 QuestionForm然后调用绑定到App的updateQuestions(update)。这适用于最外层的问题。使用对子问题所做的更改来更新App状态的最佳方法是什么?

   class Question extends Component{
      constructor(props){
        super(props)
        this.state = {
          question: props.question
        }
        this.updateInputValue = this.updateInputValue.bind(this)
      }
      .....
      updateInputValue(e){
        let { name, value } = e.target, 
            question = {...this.props.question }
        if( !name ){
          value = e.target.parentElement.getAttribute('name') || 
                  e.target.getAttribute('name')
          name = 'type'
        } 
        question[name] = value
        this.setState({question: question})
        this.props.updateParent(this.props.id, question)
      }

这就是我如何在问题中呈现每个问题的子问题 render()组件

{ question.subQ.map( (q, i) => 
                  <Question key={i} 
                           question={q} 
                        updateParent={this.props.updateParent} /> ) }

QuestionForm组件中的updateParent函数

      updateParent = (key, prop) => {
        let questions = {...this.state.questions }
        questions[key] = prop
        this.props.updateQuestions(questions)
      }

最后,App组件

          class App extends Component {
        constructor(props){
          super(props)
          this.state = {
            questions: sample,
            activeItem: 'Create'
          }
          this.checkStorage = checkStorage
          this.addQuestion = addQuestion.bind(this)
          this.handleTabClick = this.handleTabClick.bind(this)
          this.updateQuestions = this.updateQuestions.bind(this)
        }

        updateQuestions(update){
          this.setState({questions: update})
        }

我正在考虑采用自下而上的方法,跟踪parentKeys并爬上树,直到'isSub'=== false。有没有更好的方法来解决这个问题?

1 个答案:

答案 0 :(得分:0)

如果App要存储您的问题状态,我认为最简单的方法就是给App一个这样的updateQuestion方法:

updateQuestion(path, value) {
  const { questions } = this.state;
  _.set(questions, path, value);
  this.setState({ questions });
}

在这里,我们使用lodash's set method来横向数据结构并改变您需要的任何值。现在,我们可以绑定此函数并将其作为每个问题的支柱传递下来,并根据需要传递每个子问题。

然后,在渲染方法中,当您将每个问题映射到数据数组时,动态地为其分配一个path道具,该道具反映了您在该状态下将要更改的值的位置问题调用updateQuestion。

将App的state.questions(或其中的一部分)传递给每个Question作为prop,你可以避免让它们保持自己的状态,这意味着除非你需要生命周期钩子,你可以把问题变成一个功能组件

老实说,当你发现自己不得不冒泡这样的状态时,是时候问自己,redux是不是可行的方法。如果您之前没有使用它,您将拥有一些初始增长的主电源,但它将为您节省大量精力和不必要的复杂性。