我有以下React组件:

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>
            ...
        );
    }

};

控制台给了我未定义-有人知道这段代码有什么问题吗?


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

首先要做的是:

It's important to understand how React works, so you can do things properly (protip: it's super worth running through the React tutorial on the React website. It's well written, and covers all the basics in a way that actually explains how to do things). "Properly" here means that you're not writing a web page, you're writing the user interface for an application that happens to be rendered in a browser; all the actual user interface work happens in React, not in "what you're used to from writing a web page" (this is why React apps really are "apps", not "web pages").

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

组件的属性是由创建该组件实例的父组件声明的,父组件可以在其整个生命周期中修改该实例 组件自己的内部状态,它可以在自己的生命周期中自我修改。

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

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

In this programming model, the app's internal state is the final authority, rather than "the UI your users look at and interact with": if a user tries to type something in an input field, and you did not write anything to handle that, nothing will happen: the UI is a reflection of the application state, not the other way around. Effectively, the browser DOM is almost an afterthought in this programming model: it just happens to be a super convenient UI framework that the entire planet is virtually guaranteed to have access to (but it's not the only one React knows how to work with)

具体例子

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

You wrote a component to manage (i.e. both store and present) some string data for your users, with an onChange function for handling user data. Your component's rendering code is used by React to generate a virtual DOM that contains an input component (not a DOM <input> element), and binds your onChange handler to that component so that it can be called with React event data (so note that this is not a DOM change event listener, and does not get the same event data that regular DOM event listeners do). The React library then translates that virtual DOM into a UI users can interact with, and that it will update as the application state changes. Since it's running in the browser, it builds an HTML input element.

然后,你的用户尝试实际与输入元素交互:

Your user clicks on the input element and starts typing. Nothing happens to the input element yet. Instead, the input events get intercepted by React and killed off immediately. React turns the browser event into a React event, and calls the onChange function for the virtual DOM component with the React event data. That function may do something, based on what how you wrote it, and in this case you almost certainly wrote it to update the state of your component with what the user (tried to) type. If a state update gets scheduled, React will run that state update in the near future, which will trigger a render pass after the update. During the render pass, it checks to see if the state is actually different, and if so, it generates a temporary second virtual DOM, which it compares to (a part of) your application's virtual DOM, determines which set of add/update/remove operations it needs to perform on you application's virtual DOM so that it looks the same as the new temporary one, then applies those operations and throws away the temporary virtual DOM again. It then updates the UI so that it reflects what the virtual DOM now looks like. And after all of that, we finally have an updated DOM on the page the user is actually looking at, and they see what they typed in the input element.

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

重要的是要记住,所有这些都是即时有效地发生的,所以对你的用户来说,他们在输入元素中输入文本的方式与他们在任何随机网页中输入文本的方式是一样的,但在底层,事情不能有更大的不同,但仍然导致相同的结果。

所以,有了这些,让我们看看如何从React中的元素中获取值:

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

从React 16开始(从15.5开始软启动),createClass调用不再受支持,需要使用类语法。这改变了两件事:明显的类语法,以及createClass可以“免费”做的thiscontext绑定,所以为了确保事情仍然正常工作,确保你在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的时候,都有一句谚语“你做错了”。您的类已经定义了对象原型,因此已经定义了实例上下文。不要把绳子放在上面;使用正常的事件转发,而不是在构造函数中复制所有函数调用,因为这种复制增加了错误表面,并使跟踪错误变得更加困难,因为问题可能在构造函数中,而不是在调用代码的地方。

"But then it's constantly making and throwing away functions on rerenders!" and that may be true but you're not going to notice. Nor are your users. If event handler garbage collection is your performance bottleneck, so much has already gone wrong that you need to stop and rethink your design: the reason React works so incredibly well is because it does not update the entire UI, it only updates the parts that change, and in a well designed UI, the time that most of your UI spends not changing drastically outnumbers the time small parts of your UI spend updating.

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

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

如果你不需要完整的类代码,一个实例函数就可以了,那么你现在可以使用useState钩子来获得一个状态变量,它的更新函数,其工作原理与上面的例子大致相同,除了没有“通用的”setState函数调用,并为你处理的每个值使用一个专用的状态setter:

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>
  );
}

Previously the unofficial distinction between classes and function components was "function components don't have state", so we can't hide behind that one anymore: the difference between function components and classes components can be found spread over several pages in the very well-written react documentation (no shortcut one liner explanation to conveniently misinterpret for you!) which you should read so that you know what you're doing and can thus know whether you picked the best (whatever that means for you) solution to program yourself out of a problem you're having.

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来安排状态更新,而渲染使用this.state.inputValue的事实意味着,当它在更新状态后重新呈现时,用户将看到基于他们键入的更新文本。

基于评论的增编

Given that UI inputs represent state values (consider what happens if a user closes their tab midway, and the tab is restored. Should all those values they filled in be restored? If so, that's state). That might make you feel like a large form needs tens or even a hundred input forms, but React is about modeling your UI in a maintainable way: you do not have 100 independent input fields, you have groups of related inputs, so you capture each group in a component and then build up your "master" form as a collection of groups.

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']}/>
    });
  }
});

你的错误是因为你使用类,当使用类时,我们需要绑定函数与此,以便工作得很好。不管怎么说,有很多教程告诉我们为什么要用“this”,以及“this”在javascript中是做什么的。

如果你修正了提交按钮,它应该是工作的:

<button type="button" onClick={this.onSubmit.bind(this)} className="btn">Save</button>

如果你想在控制台显示输入值你应该使用var title = this。title。value;

我成功地把它绑定到函数上 updateInputValue (evt)

这一点。updateInputValue = this.updateInputValue.bind(this);

然而,输入值={this.state。inputValue}… 结果不是什么好主意。

以下是babel ES6的完整代码:

class InputField extends React.Component{

    
  constructor(props){
   super(props);
   //this.state={inputfield: "no value"};   
   this.handleClick = this.handleClick.bind(this);
   this.updateInputValue = this.updateInputValue.bind(this);
  }
  
  handleClick(){
   console.log("trying to add picture url");
   console.log("value of input field : "+this.state.inputfield);
   
  }
 
  updateInputValue(evt){
    //console.log("input field updated with "+evt.target.value);
    this.state={inputfield: evt.target.value};   
    
  }

  render(){
    var r; 
    r=<div><input type="text" id="addpixinputfield" 
            onChange={this.updateInputValue} />
      <input type="button" value="add" id="addpix" onClick={this.handleClick}/>
      </div>;    
    return r;
   }
}

你可以在不添加“onChange”函数的情况下获得输入值。

只需在输入元素中添加一个'ref attr:

然后用这个。引用以在需要时获取输入值。

在react 16中,我使用

<Input id="number" 
       type="time" 
       onChange={(evt) => { console.log(evt.target.value); }} />

通过这样做来获得输入字段值:

import React, { Component } from 'react';

class App extends Component {

constructor(props){
super(props);

this.state = {
  username : ''
}

this.updateInput = this.updateInput.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}


updateInput(event){
this.setState({username : event.target.value})
}


handleSubmit(){
console.log('Your input value is: ' + this.state.username)
//Send state to the server code
}



render(){
return (
    <div>
    <input type="text" onChange={this.updateInput}></input>
    <input type="submit" onClick={this.handleSubmit} ></input>
    </div>
  );
}
} 

//output
//Your input value is: x

你应该在MyComponent extends React类下使用构造函数。组件

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

然后你会得到标题的结果

// On the state
constructor() {
  this.state = {
   email: ''
 }
}

// Input view ( always check if property is available in state {this.state.email ? this.state.email : ''}

<Input 
  value={this.state.email ? this.state.email : ''} 
  onChange={event => this.setState({ email: event.target.value)}
  type="text" 
  name="emailAddress" 
  placeholder="johdoe@somewhere.com" />

将ref='title'更改为:ref='title'并删除name='title' 然后删除var title = this。标题和写作:

console.log(this.refs.title.value)

此外,你应该添加.bind(this)到this. onsubmit

(它在我的情况下工作,这是非常相似的,但不是onClick,我有onSubmit={…},它被放在form (<form onSubmit={…} > < / >形式)

如果你使用类组件,那么只有3个步骤-首先你需要为你的输入文件声明状态,例如这个。State = {name: "}。其次,你需要写一个函数来设置状态,当它在下面的例子中发生变化时,它是setName(),最后你必须写输入jsx,例如< input value={this.name} onChange ={this.setName}/>

import React, { Component } from 'react'

export class InputComponents extends Component {
    constructor(props) {
        super(props)

        this.state = {
             name:'',
             agree:false
        }
        this.setName = this.setName.bind(this);
        this.setAgree=this.setAgree.bind(this);
    }

    setName(e){
        e.preventDefault();
        console.log(e.target.value);
        this.setState({
            name:e.target.value
        })
    }
    setAgree(){
        this.setState({
            agree: !this.state.agree
        }, function (){
            console.log(this.state.agree);
        })
    }
    render() {
        return (
            <div>
                <input type="checkbox" checked={this.state.agree} onChange={this.setAgree}></input>
                < input value={this.state.name} onChange = {this.setName}/>
            </div>
        )
    }
}

export default InputComponents
export default class MyComponent extends React.Component {

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

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

};

给<input>一个唯一的id

<input id='title' ...>

然后使用标准的Web API在DOM中引用它

const title = document.getElementById('title').value

不需要在每次按键时不断更新React状态。只需在需要时获取值即可。

使用不受控字段:

export default class MyComponent extends React.Component {

    onSubmit(e) {
        e.preventDefault();
        console.log(e.target.neededField.value);
    }

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

};

最简单的方法是使用箭头函数

箭头函数的代码

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>
        ...
    );
}

};

export default class App extends React.Component{
     state={
         value:'',
         show:''
      }

handleChange=(e)=>{
  this.setState({value:e.target.value})
}

submit=()=>{
   this.setState({show:this.state.value})
}

render(){
    return(
        <>
          <form onSubmit={this.submit}>
             <input type="text" value={this.state.value} onChange={this.handleChange} />
             <input type="submit" />
          </form>
          <h2>{this.state.show}</h2>
        </>
        )
    }
}

在功能组件中:-

export default function App(){

const [state, setState] = useState({
        value:'',
        show:''
    });

const handleChange = (e) => {
    setState({value: e.target.value})
}

const submit = () => {
    setState({show: state.value})
}

return(
        <>
            <form onSubmit={()=>submit()}>
                <input type="text" value={state.value} onChange={(e)=>handleChange(e)} />
                <input type="submit" />
            </form>
            <h2>{state.show}</h2>
        </>
)}

功能组件

使用状态

返回一个有状态值和一个更新它的函数。 在初始呈现期间,返回的状态(state)与作为第一个参数传递的值(initialState)相同。 setState函数用于更新状态。它接受一个新的状态值,并对组件的重新呈现进行排队。 SRC——> https://reactjs.org/docs/hooks-reference.html#usestate

useRef

useRef返回一个可变的ref对象,其.current属性初始化为传递的参数(initialValue)。返回的对象将在组件的整个生命周期内持续存在。 SRC——> https://reactjs.org/docs/hooks-reference.html#useref

import { useRef, useState } from "react";

export default function App() {
  const [val, setVal] = useState('');
  const inputRef = useRef();

  const submitHandler = (e) => {
    e.preventDefault();

    setVal(inputRef.current.value);
  }

  return (
    <div className="App">
      <form onSubmit={submitHandler}>
        <input ref={inputRef} />
        <button type="submit">Submit</button>
      </form>

      <p>Submit Value: <b>{val}</b></p>
    </div>
  );
}

React版本:17.0.1 a)使用功能组件 b)使用hook: useState()管理状态。

编写并运行上面的代码:

import React, {useState} from 'react';

const InputElement = () => {
  const [inputText, setInputText] = useState('');

  return (
   <div> 
        <input
              onChange={(e) => {
                  setInputText(e.target.value);
                   }                   
             }
             placeholder='Enter Text'
       />
       {inputText}
   </div>
 );
}

求解方案算法类似于双向数据绑定:

input <=> DATA_MODEL <=> Label_Text