【问题标题】:ReactJS: update a controlled input field problemReactJS:更新受控输入字段问题
【发布时间】:2019-07-17 08:08:53
【问题描述】:

我一直在阅读一些关于 SO 的主题,但我不知道如何解决这个问题或为什么会发生这种情况。有人可以像我 5 岁那样解释吗?

警告:组件正在将文本类型的受控输入更改为 不受控制。输入元素不应从受控切换到 不受控制(反之亦然)。决定使用受控或 组件生命周期内不受控制的输入元素

我正在开发课程创建器,用户必须能够打开现有课程,因此输入字段必须以编程方式填充现有课程的内容。

我的构造函数:

  constructor(props) {

    super(props);

    this.state = {
                  lessonID: -1,
                  sectionsArray: [],
                  title: 'No title',
                  type: 'r',
                  language: 'gb',
                  book: 'booka',
                  level: '1',

                  loading: false,

                  saved: true,

                  messageBox: '',

                  lessonOpenModal: false,

    }

    this._state = this.state;

    this.updateSectionsFromChild = this.updateSectionsFromChild.bind(this);

    this.sectionAdd = this.sectionAdd.bind(this);
    this.sectionRemove = this.sectionRemove.bind(this);

    this.menuInput = this.menuInput.bind(this);
    this.menuDropDown = this.menuDropDown.bind(this);

    this.lessonCreate = this.lessonCreate.bind(this);
    this.lessonSave = this.lessonSave.bind(this);
    this.lessonDelete = this.lessonDelete.bind(this);
    this.lessonOpen = this.lessonOpen.bind(this);

    this.sections = [];

    }

这是更新受控组件的函数:

  menuDropDown(event, data) {
    this.setState({
      [data.name]: data.value,
      saved: false,
    });

    console.log(data.name);
    console.log(data.value);
  }

  menuInput(event) {
    this.setState({
      [event.target.name]: event.target.value,
      saved: false,
    });
}

然后这是检索课程并尝试更新状态的代码部分:

  async openLesson(lessonID) {
    await ARLessonOpen(lessonID).then((result) => {

      this.setState(this._state);

      this.setState({
        id: result.lesson.id,
        language: result.lesson.language,
        book: result.lesson.book, // this is a drop down, and it's not causing errors
        type: result.lesson.type, // this is a drop down, and it's not causing errors
        level: result.lesson.level, // this is a drop down, and it's not causing errors
        title: result.lesson.title, // this is an input, and IT'S THE ISSUE

        sectionsArray: result.sections.map((section, i) => ({
          key: i,
          id: i,
          title: section.title,
          duration: section.duration,
          content: section.content,
        }))
      })

    }).catch(function(error) {
      console.log(error);
    });
  }

唯一不起作用的字段是“标题”,我不明白为什么。如何以编程方式更新输入值?

JSX:

  renderSections = () => {

    if (this.state.sectionsArray.length > 0) {
      return this.state.sectionsArray.map((section, i) =>
        <LessonSection
          key={section.id}
          id={section.id}
          title={section.title}
          duration={section.duration}
          content={section.content}
          sectionRemove={this.sectionRemove}
          sectionAdd={this.sectionAdd}
          updateSectionsFromChild={this.updateSectionsFromChild}
        />
      )
    } else {
      return (
        <div style={{color: 'black'}}> 
          <Button
            size='mini'
            icon='plus square outline'
            onClick={this.sectionAdd} />
          Add a section to start creating your lesson.
        </div>
      )
    }
  }

  render() {

    return (
      <div className='Lesson-editor'>

        {this.state.messageBox}

        <div style={{display: 'none'}}>

          <DefaultLoader
            active={this.state.loading}
            message={this.state.message}
          />

        </div>

        <div className="Lesson-editor-menu Small-font">

          <div className="Menu-buttons">

            <Button
              size='mini'
              icon='plus square outline'
              onClick={this.sectionAdd} />

            <Button
              size='mini'
              icon='file outline'
              onClick={this.lessonCreate} />

            <DialoglessonOpen
              open={this.state.lessonOpenModal}
              actionOnLessonSelected={(lessonID) => this.openLesson(lessonID)}

              onCancel={() => this.setState({lessonOpenModal: false})} />

            <Button size='mini' icon='open folder outline' text='Open lesson' description='ctrl + o' onClick={this.lessonOpen} />

            <Button
              size='mini'
              icon='save outline'
              onClick={this.lessonSave} />

            <Button
              size='mini'
              icon='delete'
              onClick={this.lessonDelete} />

            <Button
              size='mini'
              icon='delete'
              color='red'
              onClick={ARClearTables} />

          </div>

          <Input
            className='title'
            fluid
            placeholder='Lesson title'
            value={this.state.title}
            name='title'
            onChange={this.menuInput}
          />

          <div>

            <Dropdown
              fluid
              compact
              placeholder='Language'
              search
              selection
              options={lessonLanguages}
              //defaultValue='gb'
              value={this.state.language}
              name='language'
              onChange={this.menuDropDown}
            />

            <Dropdown
              fluid
              compact
              placeholder='Book'
              search
              selection
              options={lessonBooks}
              //defaultValue='booka'
              value={this.state.book}
              name='book'
              onChange={this.menuDropDown}
            />

            <Dropdown
              fluid
              compact
              placeholder='Lesson type'
              search
              selection
              options={lessonTypes}
              defaultValue='r'
              name='type'
              onChange={this.menuDropDown}
            />

            <Dropdown
              fluid
              compact
              placeholder='Lesson level'
              search
              selection
              options={lessonLevels}
              defaultValue='1'
              name='level'
              onChange={this.menuDropDown}
            />

          </div>

        </div>

        <div className='Sections'>
          { this.renderSections() }
        </div>

      </div>
    );
  }
}

【问题讨论】:

  • 如果我们看到你的 jsx 可能更容易推断。
  • 完成!此外,下拉列表只是不抛出错误,但还没有更新实际的下拉列表(正在处理它)。

标签: javascript reactjs input


【解决方案1】:

输入表单字段的初始值不能为 undefined 或 null,如果您想稍后控制它。它应该是一个空字符串。如果您提供 undefined 或 null,则它是不受控制的组件。

在您的代码中,React 看不到输入字段的任何值,因此 React 认为它是第一次挂载时不受控制的组件。后来,当你给组件添加一个值时,React 警告你在你没有提供一个值(非受控组件)之后你不能给一个值(受控组件)

【讨论】:

  • 我要更新的输入字段(它是一个文本框)的值设置为 value={this.state.title}(你可以在我粘贴的最后一段代码中找到它) ,并且该值在构造函数中设置为标题:'No title',因此它是一个受控组件,对吗?我不明白我做错了什么。
【解决方案2】:

我想通了:问题是我的代码中有错误。我将null 值分配给state 中的输入字段值。

 async openLesson(lessonID) {
    await ARLessonOpen(lessonID).then((result) => {

      this.setState(this._state);

      this.setState({

        /* HERE: I try to access result.lesson but it's null! I should
            use result.lesson[0]. So the problem is that I was 
            assigning a null value to the input field resulting in the error */

        id: result.lesson.id,
        language: result.lesson.language,
        book: result.lesson.book,
        type: result.lesson.type,
        level: result.lesson.level, 
        title: result.lesson.title,

        sectionsArray: result.sections.map((section, i) => ({
          key: i,
          id: i,
          title: section.title,
          duration: section.duration,
          content: section.content,
        }))
      })

    }).catch(function(error) {
      console.log(error);
    });
  }

【讨论】:

    猜你喜欢
    • 2019-10-24
    • 2018-06-27
    • 1970-01-01
    • 2020-09-15
    • 2021-01-30
    • 1970-01-01
    • 1970-01-01
    • 2023-02-08
    • 1970-01-01
    相关资源
    最近更新 更多