如何使用 ReactJS 获取输入字段的值?

新手上路,请多包涵

我有以下反应组件:

export default class MyComponent extends React.Component {

    onSubmit(e) {
        e.preventDefault();
        var title = this.title;
        console.log(title);
    }

    render(){
        return (
            ...
            <form className="form-horizontal">
                ...
                <input type="text" className="form-control" ref={(c) => this.title = c} name="title" />
                ...
            </form>
            ...
            <button type="button" onClick={this.onSubmit} className="btn">Save</button>
            ...
        );
    }

};

控制台给了我 undefined 的 - 任何想法这段代码有什么问题?

原文由 JoeTidee 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 807
2 个回答

您应该使用 MyComponent 类下的构造函数 extends React.Component

 constructor(props){
 super(props);
 this.onSubmit = this.onSubmit.bind(this);
 }

然后你会得到title的结果

原文由 Md. Maidul Islam 发布,翻译遵循 CC BY-SA 4.0 许可协议

这里有三个答案,取决于你(被迫)使用的 React 版本,以及你是否想使用钩子。

首先要做的事情:

了解 React 的工作原理很重要,这样您才能正确地做事(提示:通过 React 网站上的 React 教程 非常 值得一读。它写得很好,并且以实际解释如何做事的方式涵盖了所有基础知识) .这里的“正确”意味着您不是在编写网页,而是在为恰好在浏览器中呈现的应用程序编写用户界面;所有实际的用户界面工作都发生在 React 中,而不是“你习惯于编写网页”(这就是为什么 React 应用程序真的是“应用程序”,而不是“网页”)。

React 应用程序的渲染基于两件事:

  1. 组件的属性由创建该组件实例的任何父级声明,父级可以在其整个生命周期中修改,并且
  2. 组件自己的内部状态,它可以在自己的生命周期中自行修改。

当您使用 React 时,您明确 没有 做的是生成 HTML 元素然后使用它们:例如,当您告诉 React 使用 <input> 时,您不是在创建 HTML 输入元素,而是告诉 React 创建一个 React 输入对象,当您为 Web 编译 React 应用程序时,该对象恰好呈现为 HTML 输入元素,事件处理由 React 控制。

使用 React 时,您正在做的是生成应用程序 UI 元素,这些元素向用户展示(通常是可操作的)数据,用户交互以 定义的方式改变应用程序的状态——用户执行的操作可能会更新组件的props 或 state,React 将其用作为更改的组件生成新的 UI 表示的信号,这 可能会 导致应用程序界面的一部分更新以反映新状态。

在这个编程模型中,应用程序的内部状态是最终的权威,而不是“你的用户查看并与之交互的 UI”:如果用户试图在输入字段中键入内容,而你没有编写任何东西来处理它,什么都不会发生:UI 是应用程序状态的反映,而不是相反。实际上,浏览器 DOM 在这个编程模型中几乎是事后才想到的:它恰好是一个超级方便的 UI 框架,几乎可以保证整个星球都可以访问它(但它不是 React 唯一知道如何使用的框架)

一个具体的例子

说完这些,让我们看看用户与输入元素的交互在 React 中是如何工作的。首先,我们需要有一个 UI 元素供用户交互:

  1. 您编写了一个组件来为您的用户管理(即存储和呈现)一些字符串数据,并使用 onChange 函数来处理用户数据。
  2. React 使用您组件的渲染代码生成一个虚拟 DOM,其中包含一个 input 组件(不是 DOM <input> 元素),并将您的 onChange 绑定到处理程序该组件,以便可以使用 React 事件数据调用它(请注意,这不是 DOM change 事件监听器,并且不会获得与常规 DOM 事件监听器相同的事件数据)。
  3. React 库然后将该虚拟 DOM 转换为用户可以与之交互的 UI,并且它将随着应用程序状态的变化而更新。因为它在浏览器中运行,所以它构建了一个 HTML 输入元素。

然后,您的用户尝试与该输入元素进行实际交互:

  1. 您的用户单击输入元素并开始输入。
  2. 输入元素还没有任何反应。相反,输入事件会被 React 拦截并立即终止
  3. React 将浏览器事件转换为 React 事件,并使用 React 事件数据为虚拟 DOM 组件调用 onChange 函数。
  4. 该函数 可能会 执行某些操作,具体取决于您编写它的方式,在这种情况下,您几乎肯定会编写它来根据用户(尝试)键入的内容更新组件的状态。
  5. 如果安排了状态更新,React 将在不久的将来运行该状态更新,这将在更新后触发渲染过程。
  6. 在渲染过程中,它会检查状态是否真的不同,如果是,它会生成一个临时的第二个虚拟 DOM,并将其与应用程序的虚拟 DOM(的一部分)进行比较,确定哪一组添加/更新/删除它需要对您的应用程序的虚拟 DOM 执行的操作,以便它看起来与新的临时虚拟 DOM 相同,然后应用这些操作并再次丢弃临时虚拟 DOM。
  7. 然后它会更新 UI,以反映虚拟 DOM 现在的样子。
  8. 在所有这一切之后,我们终于在用户实际查看的页面上有了一个更新的 DOM,他们可以看到他们在输入元素中输入的内容。

所以这与常规浏览器模型完全不同:不是用户 首先 通过在文本框中键入内容来更新 UI 数据,然后我们的代码读取“该文本框的当前值”以确定其状态是什么, React 已经知道状态是什么,并 首先 使用事件更新状态,从而导致 UI _更新_。

重要的是要记住,所有这些都是立即有效发生的,所以对于您的用户 _来说_,他们将文本键入输入元素的方式与他们在任何随机网页上输入的方式相同,但在幕后,事情不会更多不同,但仍然导致相同的结果。

因此,了解了这些,让我们看看如何从 React 中的元素获取值:

组件类和 ES6(React 16+ 和 15.5 过渡版)

从 React 16(和 15.5 的软启动)开始,不再支持 createClass 调用,需要使用类语法。这改变了两件事:明显的类语法,还有 this 上下文绑定 createClass 可以“免费”执行,因此要确保事情仍然有效,请确保您正在使用“ this 上下文保留匿名函数的符号 onWhatever 处理程序,例如 onChange 在这里:我们在代码中使用

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.reset();
  }

  reset() {
    // Always set the initial state in its own function, so that
    // you can trivially reset your components at any point.
    this.state = {
      inputValue: ''
    };
  }

  render() {
    return (
      // ...
      <input value={this.state.inputValue} onChange={evt => this.updateInputValue(evt)}/>
      // ...
    );
  },

  updateInputValue(evt) {
    const val = evt.target.value;
    // ...
    this.setState({
      inputValue: val
    });
  }
});

您可能还看到人们在他们的构造函数中使用 bind 来处理所有事件处理函数,如下所示:

 constructor(props) {
  super(props);
  this.handler = this.handler.bind(this);
  ...
}

render() {
  return (
    ...
    <element onclick={this.handler}/>
    ...
  );
}

不要那样做。

几乎任何时候你使用 bind ,谚语“你做错了”都适用。您的类已经定义了对象原型,因此也已经定义了实例上下文。不要把 bind 放在最上面;使用正常的事件转发而不是在构造函数中重复所有函数调用,因为这种重复会增加错误面,并使跟踪错误变得更加困难,因为问题可能出在构造函数中而不是调用代码的地方。

“但随后它不断地在重新渲染时创建和丢弃功能!”这可能是真的,但你不会注意到。你的用户也不是。如果事件处理程序垃圾收集是您的性能瓶颈,那么已经出现太多错误,您需要停下来重新考虑您的设计:React 如此出色的原因是因为它不会更新整个 UI,它只会更新发生变化的部分,并且在设计良好的 UI 中,大部分 UI 花在不改变上的时间大大超过了 UI 的一小部分花在更新上的时间。

带钩子的功能组件(React 16.8+)

从 React 16.8 开始,函数组件(即字面上只是一个函数,它接受一些 props 作为参数,可以像组件类的实例一样使用,而无需编写类)也可以被赋予状态,通过使用 钩子

如果您不需要完整的类代码,并且单个实例函数就可以,那么您现在可以使用 useState 挂钩来为自己获取单个状态变量及其更新函数,其工作原理大致相同如上面的示例,除了没有“通用” setState 函数调用并为您正在使用的每个值使用一个专用状态设置器:

 import { useId, useState } from 'react';

function myFunctionalComponentFunction(props) {
  const id = useId();
  const [input, setInput] = useState(props?.value ?? '');
  return (
    <div>
    <label htmlFor={id}>Please specify:</label>
    <input id={id} value={input} onInput={e => setInput(e.target.value)}/>
    </div>
  );
}

以前类和函数组件的非官方区别是“函数组件没有状态”,所以我们不能再躲在后面了:函数组件和类组件的区别可以在 very well 的好几页中找到- 编写的 React 文档(没有捷径可以方便地为您曲解!)您应该阅读它,以便您知道自己在做什么,从而知道您是否选择了最好的(无论对您意味着什么)解决方案来为自己编程出于你遇到的问题。

React 15 及以下版本,使用旧版 ES5 和 createClass

为了正确地做事,您的组件有一个状态值,它通过输入字段显示,我们可以通过使该 UI 元素将更改事件发送回组件来更新它:

 var Component = React.createClass({
  getInitialState: function() {
    return {
      inputValue: ''
    };
  },

  render: function() {
    return (
      //...
      <input value={this.state.inputValue} onChange={this.updateInputValue}/>
      //...
    );
  },

  updateInputValue: function(evt) {
    this.setState({
      inputValue: evt.target.value
    });
  }
});

所以我们告诉 React 使用 updateInputValue 函数来处理用户交互,使用 setState 来安排状态更新,事实上 render this.state.inputValue 7b20b- --- 意味着当它在更新状态后重新呈现时,用户将看到基于他们键入的内容的更新文本。

基于评论的附录

鉴于 UI 输入代表状态值(考虑如果用户中途关闭他们的选项卡并且选项卡被恢复会发生什么。他们填写的所有这些值是否应该被恢复?如果是这样,那就是状态)。这可能会让你觉得一个大表单需要几十个甚至一百个输入表单,但 React 是以可维护的方式建模你的 UI:你没有 100 个独立的输入字段,你有一组相关的输入,所以你捕获每个在一个组件中分组,然后将您的“主”表单构建为组的集合。

 MyForm:
  render:
    <PersonalData/>
    <AppPreferences/>
    <ThirdParty/>
     ...

这也比一个巨大的单一表单组件更容易维护。将组拆分为具有状态维护的组件,其中每个组件一次只负责跟踪几个输入字段。

您可能还会觉得写出所有这些代码是“一件麻烦事”,但这是一种错误的节省:不是您的开发人员,包括未来的您,实际上会从看到所有这些输入明确连接起来而受益匪浅,因为它使代码路径更容易跟踪。但是,您始终可以优化。例如,您可以编写一个状态链接器

MyComponent = React.createClass({
  getInitialState() {
    return {
      firstName: this.props.firstName || "",
      lastName: this.props.lastName || ""
      ...: ...
      ...
    }
  },
  componentWillMount() {
    Object.keys(this.state).forEach(n => {
      let fn = n + 'Changed';
      this[fn] = evt => {
        let update = {};
        update[n] = evt.target.value;
        this.setState(update);
      });
    });
  },
  render: function() {
    return Object.keys(this.state).map(n => {
      <input
        key={n}
        type="text"
        value={this.state[n]}
        onChange={this[n + 'Changed']}/>
    });
  }
});

原文由 Mike ‘Pomax’ Kamermans 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题