Làm thế nào để có được giá trị của một trường đầu vào bằng ReactJS?


188

Tôi có thành phần React sau:

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

};

Bảng điều khiển đang cho tôi undefined- có ý tưởng nào sai với mã này không?


7
this.onSubmit.bind(this);
zerkms

Rất vui - muốn thêm nó dưới dạng câu trả lời và tôi sẽ đánh dấu vào đó (?)
JoeTidee

2
Nếu e.target.valuekhông có sự ràng buộc thì sao?
omarjmh

1
e.target.value sẽ nhắm mục tiêu vào nút chứ không phải trường nhập liệu?
JoeTidee

Bạn cần liên kết onSubmitphương thức với nút gửi (phần tử DOM) khi được nhấp (tức là onClick={this.onSubmit.bind(this)}). Và nếu bạn muốn truy cập giá trị của đầu vào tiêu đề ở dạng bạn có thể sử dụng onSubmit(event) { const title = event.target.elements.title.value; }.
tfmontague

Câu trả lời:


10

Bạn nên sử dụng hàm tạo trong lớp MyComponent mở rộng React.Component

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

Sau đó, bạn sẽ nhận được kết quả của tiêu đề


310

Có ba câu trả lời ở đây, tùy thuộc vào phiên bản React mà bạn (buộc phải) làm việc (ing) với, và bạn có muốn sử dụng hook không.

Điều đầu tiên trước tiên:

Điều quan trọng là phải hiểu như thế nào Phản ứng công trình, vì vậy bạn có thể làm những việc đúng cách (protip: nó là siêu đáng chạy qua Phản ứng tập thể dục hướng dẫn trên Phản ứng trang web của nó cũng bằng văn bản, và bao gồm tất cả những điều cơ bản trong một cách mà thực sự giải thích làm thế nào để làm. nhiều thứ). "Chính xác" ở đây có nghĩa là bạn đang viết một giao diện ứng dụng sẽ được hiển thị trong trình duyệt; tất cả các giao diện đều diễn ra trong React, không phải trong "những gì bạn đã từng sử dụng nếu bạn đang viết một trang web" (đây là lý do tại sao các ứng dụng React là "ứng dụng", không phải là "trang web").

Các ứng dụng React được kết xuất dựa trên hai điều:

  1. các thuộc tính của thành phần như được khai báo bởi bất kỳ cha mẹ nào tạo ra một thể hiện của thành phần đó, mà cha mẹ có thể sửa đổi trong suốt vòng đời của nó và
  2. trạng thái bên trong của chính thành phần, mà nó có thể tự sửa đổi trong suốt vòng đời của chính nó.

Những gì bạn rõ ràng không làm khi bạn sử dụng React đang tạo các phần tử HTML và sau đó sử dụng các phần tử đó: khi bạn bảo React sử dụng <input>, chẳng hạn, bạn không tạo phần tử đầu vào HTML, bạn đang nói với React để tạo đối tượng nhập React điều đó xảy ra để hiển thị dưới dạng phần tử đầu vào HTML và xử lý sự kiện nhìn vào, nhưng không được kiểm soát bởi các sự kiện đầu vào của phần tử HTML.

Khi sử dụng React, những gì bạn đang làm là tạo ra các thành phần UI ứng dụng cung cấp cho người dùng dữ liệu (thường có thể thao tác), với sự tương tác của người dùng thay đổi trạng thái của Thành phần, điều này có thể khiến một phần của giao diện ứng dụng của bạn phản ánh trạng thái mới. Trong mô hình này, trạng thái luôn là cơ quan cuối cùng, không phải "bất kỳ thư viện UI nào được sử dụng để hiển thị nó", mà trên web là DOM của trình duyệt. DOM gần như là một suy nghĩ sau trong mô hình lập trình này: đó chỉ là khung UI cụ thể mà React tình cờ đang sử dụng.

Vì vậy, trong trường hợp của một phần tử đầu vào, logic là:

  1. Bạn nhập phần tử đầu vào,
  2. chưa có gì xảy ra với phần tử đầu vào của bạn, sự kiện đã bị React chặn lại và tiêu diệt ngay lập tức ,
  3. Phản ứng chuyển tiếp sự kiện đến chức năng bạn đã thiết lập để xử lý sự kiện,
  4. chức năng đó có thể lên lịch cập nhật trạng thái,
  5. nếu có, React chạy cập nhật trạng thái đó (không đồng bộ!) và sẽ kích hoạt rendercuộc gọi sau khi cập nhật, nhưng chỉ khi cập nhật trạng thái thay đổi trạng thái.
  6. chỉ sau khi kết xuất này diễn ra, giao diện người dùng mới hiển thị rằng bạn "đã gõ một chữ cái".

Tất cả điều đó xảy ra trong một phần nghìn giây, nếu không phải là ít hơn, do đó, có vẻ như bạn đã nhập vào phần tử đầu vào giống như cách bạn đã sử dụng từ "chỉ sử dụng một yếu tố đầu vào trên trang", nhưng đó hoàn toàn không phải là điều gì đã xảy ra.

Vì vậy, như đã nói, về cách nhận giá trị từ các phần tử trong React:

Phản ứng 15 trở xuống, với ES5

Để thực hiện đúng cách, thành phần của bạn có giá trị trạng thái, được hiển thị thông qua trường đầu vào và chúng tôi có thể cập nhật nó bằng cách làm cho phần tử UI đó gửi các sự kiện thay đổi trở lại thành phần:

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

Vì vậy, chúng tôi nói với React sử dụng updateInputValuechức năng để xử lý sự tương tác của người dùng, sử dụng setStateđể lên lịch cập nhật trạng thái và thực tế là renderchạm vào this.state.inputValuecó nghĩa là khi nó đăng ký lại sau khi cập nhật trạng thái, người dùng sẽ thấy văn bản cập nhật dựa trên nội dung họ đã nhập.

phụ lục dựa trên ý kiến

Cho rằng các đầu vào UI đại diện cho các giá trị trạng thái (xem xét điều gì xảy ra nếu người dùng đóng tab giữa chừng và tab được khôi phục. Có nên khôi phục tất cả các giá trị mà chúng đã điền không? Nếu vậy, đó là trạng thái). Điều đó có thể khiến bạn cảm thấy như một hình thức lớn cần hàng chục hoặc thậm chí một trăm biểu mẫu đầu vào, nhưng React nói về việc mô hình hóa giao diện người dùng của bạn theo cách có thể duy trì: bạn không có 100 trường đầu vào độc lập, bạn có các nhóm đầu vào liên quan, do đó bạn nắm bắt từng nhóm trong một thành phần và sau đó xây dựng biểu mẫu "chính" của bạn dưới dạng tập hợp các nhóm.

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

Điều này cũng dễ bảo trì hơn nhiều so với một thành phần đơn khổng lồ. Chia nhóm thành các Thành phần có bảo trì trạng thái, trong đó mỗi thành phần chỉ chịu trách nhiệm theo dõi một vài trường đầu vào tại một thời điểm.

Bạn cũng có thể cảm thấy như "thật rắc rối" khi viết ra tất cả mã đó, nhưng đó là một sự tiết kiệm sai: các nhà phát triển không phải là bạn, kể cả bạn trong tương lai, thực sự được hưởng lợi rất nhiều từ việc nhìn thấy tất cả những đầu vào đó được nối rõ ràng, bởi vì nó làm cho đường dẫn mã dễ theo dõi hơn nhiều. Tuy nhiên, bạn luôn có thể tối ưu hóa. Chẳng hạn, bạn có thể viết một trình liên kết trạng thái

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

Tất nhiên, có những phiên bản cải tiến này, vì vậy hãy truy cập https://npmjs.com và tìm kiếm giải pháp liên kết trạng thái React mà bạn thích nhất. Nguồn mở chủ yếu là tìm kiếm những gì người khác đã làm và sử dụng nó thay vì tự viết mọi thứ từ đầu.

Phản ứng 16 (và 15,5 chuyển tiếp) và 'hiện đại' JS

Kể từ React 16 (và bắt đầu mềm với 15,5), createClasscuộc gọi không còn được hỗ trợ và cú pháp lớp cần được sử dụng. Điều này thay đổi hai điều: cú pháp lớp rõ ràng, nhưng cũng là thisràng buộc ngữ cảnh createClasscó thể "miễn phí", vì vậy để đảm bảo mọi thứ vẫn hoạt động, hãy đảm bảo bạn đang sử dụng ký hiệu "mũi tên béo" để thisbảo vệ ngữ cảnh các hàm ẩn danh trong onWhatevertrình xử lý, chẳng hạn như các onChangesử dụng chúng trong các mã ở đây:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: ''
    };
  }

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

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

Bạn cũng có thể đã thấy mọi người sử dụng bindtrong hàm tạo của họ cho tất cả các hàm xử lý sự kiện của họ, như thế này:

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

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

Đừng làm vậy.

Hầu như bất cứ lúc nào bạn đang sử dụng bind, câu tục ngữ "bạn đang làm sai" đều được áp dụng. Lớp của bạn đã định nghĩa nguyên mẫu đối tượng và do đó đã xác định bối cảnh thể hiện. Đừng đặt lên bindhàng đầu; sử dụng chuyển tiếp sự kiện thông thường thay vì sao chép tất cả các lệnh gọi hàm của bạn trong hàm tạo, bởi vì sự trùng lặp đó làm tăng bề mặt lỗi của bạn và khiến việc theo dõi lỗi trở nên khó khăn hơn vì vấn đề có thể nằm ở hàm tạo của bạn thay vì nơi bạn gọi mã. Cũng như đặt một gánh nặng bảo trì lên những người khác mà bạn (có hoặc chọn) làm việc cùng.

Vâng, tôi biết các tài liệu phản ứng nói rằng nó ổn. Không, đừng làm.

Phản ứng 16.8, sử dụng các thành phần chức năng với móc

Kể từ React 16.8, thành phần hàm (nghĩa đen chỉ là một hàm lấy một số propsđối số có thể được sử dụng như thể nó là một thể hiện của một lớp thành phần, mà không bao giờ viết một lớp) cũng có thể được đưa ra trạng thái, thông qua việc sử dụng các hook .

Nếu bạn không cần mã lớp đầy đủ và một hàm cá thể sẽ làm, thì bây giờ bạn có thể sử dụng useStatehook để lấy cho mình một biến trạng thái duy nhất và hàm cập nhật của nó, hoạt động gần giống như các ví dụ trên, trừ khi không có các setStatecuộc gọi chức năng:

import { useState } from 'react';

function myFunctionalComponentFunction() {
  const [input, setInput] = useState(''); // '' is the initial state value
  return (
    <div>
    <label>Please specify:</label>
    <input value={input} onInput={e => setInput(e.target.value)}/>
    </div>
  );
}

Trước đây, sự khác biệt không chính thức giữa các lớp và các thành phần chức năng là "các thành phần chức năng không có trạng thái", vì vậy chúng ta không thể ẩn đằng sau điều đó nữa: sự khác biệt giữa các thành phần chức năng và các thành phần lớp có thể được tìm thấy trên một số trang rất tốt -written phản ứng tài liệu (không có phím tắt một lời giải thích lót để thuận tiện hiểu sai cho bạn!) mà bạn nên đọc để bạn biết những gì bạn đang làm và do đó có thể biết liệu bạn đã chọn (bất cứ điều gì mà phương tiện cho bạn) giải pháp tốt nhất để chương trình tự ra một vấn đề bạn đang gặp phải


4
Tôi đã đọc một vài bài báo trực tuyến nói rằng sử dụng quá nhiều trạng thái là một ý tưởng tồi. Trong một hình thức cụ thể của ứng dụng của tôi, tôi có khoảng 100 trường mẫu. Xác định một chức năng để lưu trạng thái cảm thấy như một cách làm việc khó khăn không cần thiết. Nếu tôi có thể sử dụng onClick = {this.onSubmit.bind (this)}, đây có vẻ là một cách tốt để nhận giá trị (sau đó nếu tôi muốn, hãy đặt trạng thái thành phần) - Tôi sẽ đánh giá cao một số nhận xét về điều này.
JoeTidee

5
vì vậy hãy viết mã thông minh hơn. đầu vào biểu mẫu là trạng thái chắc chắn nhất (xem xét điều gì xảy ra nếu người dùng đóng tab giữa chừng và tab được khôi phục. Có nên khôi phục tất cả các giá trị mà chúng điền vào không? có? đó là trạng thái ), vì vậy hãy viết một chút mã bảo trì trạng thái. Facebook cũng có hàng trăm giá trị biểu mẫu và giải pháp cho sự điên rồ của họ là React. Nó hoạt động thực sự tốt. Một cách để làm cho mã của bạn dễ dàng hơn một chút, trong khi vẫn sử dụng trạng thái, là sử dụng liên kết trạng thái hai chiều , một lần nữa, được giải thích trên trang web React. Đáng đọc! =)
Mike 'Pomax' Kamermans

2
Cũng lưu ý rằng "100 trường" hầu như không liên quan: chia nhỏ biểu mẫu của bạn, vì nó không phải là 100 phần tử, đó là một số phần, mỗi phần có một số đầu vào, vì vậy hãy áp dụng thiết kế tốt và tạo cho mỗi phần thành phần riêng, với các thành phần nhóm cho biểu mẫu các nhóm. Điều này thường làm cho một thành phần chịu trách nhiệm cho ít hơn 10 đầu vào và đột nhiên kiến ​​trúc thông tin của bạn có ý nghĩa hơn rất nhiều. Biểu mẫu gửi, như một hành động của trình duyệt, tất nhiên chỉ nhìn thấy "biểu mẫu của bạn" và gửi mọi thứ trong một lần. Thiết kế UI sạch sẽ, được nhắm mục tiêu.
Mike 'Pomax' Kamermans

2
Cảm ơn các ý kiến. Tuy nhiên, tôi đã nhận thấy rằng liên kết trạng thái đã không được chấp nhận kể từ React v15.
JoeTidee

3
@JasonChing sau đó bạn chỉ đơn giản là xây dựng các lỗi tiềm năng vào mã của mình. Phản ứng được không phải là một "được tất cả, chấm dứt tất cả các" giải pháp cho các trang web, đó là một khuôn khổ cho việc xây dựng giao diện, và có nhiệm vụ quản lý nhà nước và giao diện người dùng vẽ thực tế như suy nghĩ (người dùng của bạn không tương tác với DOM, họ tương tác với Phản ứng. Các bản cập nhật DOM chỉ đơn giản là bước cuối cùng không đồng bộ (nhưng cực kỳ nhanh) để UI phản ánh trực quan trạng thái). Nếu bạn muốn bỏ qua điều đó, câu hỏi quan trọng hơn là: tại sao bạn lại sử dụng React? Bởi vì dấu hiệu tốt nhất bạn đang sử dụng sai là kết hợp React và jQuery.
Mike 'Pomax' Kamermans

17

Quản lý để có được giá trị trường đầu vào bằng cách làm một cái gì đó như thế này:

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

Tại sao sử dụng "setState"? Điều này liên quan đến việc tái hiện..không phải sao?
Luca Davanzo

15

Trong phản ứng 16, tôi sử dụng

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

không hoạt động nếu trường được điền tự động khi tải tuổi
SeanMC

4

Tôi đã thành công trong việc này bằng cách ràng buộc "cái này" với hàm updateInputValue (evt) với

this .updateInputValue = this.updateInputValue.bind (this);

Tuy nhiên, giá trị đầu vào = {this.state.inputValue} ... hóa ra không phải là ý kiến ​​hay.

Đây là mã đầy đủ trong 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;
   }
}

2

Lỗi của bạn là do bạn sử dụng lớp và khi sử dụng lớp, chúng ta cần liên kết các hàm với Điều này để hoạt động tốt. dù sao, có rất nhiều hướng dẫn tại sao chúng ta nên "cái này" và "cái này" làm gì trong javascript.

nếu bạn sửa nút gửi của mình thì nó sẽ hoạt động:

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

và ngoài ra, nếu bạn muốn hiển thị giá trị của đầu vào đó trong bảng điều khiển, bạn nên sử dụng var title = this.title.value;


2
liên kết này có thể hữu ích nếu bạn muốn biết thêm về "này"
Soroush Bk


1
// 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" />

trong khi câu trả lời của bạn có thể tốt cho câu hỏi, tốt hơn hết là thêm một số lời giải thích. Hãy dành 2 phút để thêm nó. Điều này sẽ cải thiện câu trả lời của bạn cho người dùng trong tương lai.
DaFois

chắc chắn, tôi sẽ làm điều đó
Kidali Kevin

1

Cung cấp <input>một id duy nhất

<input id='title' ...>

và sau đó sử dụng API Web tiêu chuẩn để tham chiếu nó trong DOM

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

Không cần cập nhật liên tục trạng thái React với mỗi lần nhấn phím. Đơn giản chỉ cần nhận được giá trị khi nó được yêu cầu.


0

Bạn có thể nhận giá trị đầu vào mà không cần thêm chức năng 'onChange'.

Chỉ cần thêm vào phần tử đầu vào một 'ref attr:

Và sau đó sử dụng this.refs để lấy giá trị đầu vào khi bạn cần.


3
Điều này không được khuyến khích nữa.
JoeTidee

1
Bạn có thể sử dụng chúng, nhưng bạn nên giữ luồng dữ liệu theo một hướng bằng cách sử dụng đạo cụ và cuộc gọi lại.
JoeTidee

Sẽ tốt hơn nếu thêm một ví dụ về việc thêm ref một cách chính xác, nghĩa là sử dụng một cuộc gọi lại ref thay vì một chuỗi kế thừa.
JoeTidee

0

Thay đổi ref của bạn thành: ref='title'và xóa name='title' Sau đó xóa var title = this.titlevà viết:

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

Ngoài ra, bạn nên thêm .bind(this)vàothis.onSubmit

(Nó hoạt động trong trường hợp của tôi khá giống nhau, nhưng thay vì onClicktôi có onSubmit={...}và nó được đặt ở dạng ( <form onSubmit={...} ></form>))


0

nếu bạn sử dụng thành phần lớp thì chỉ có 3 bước - trước tiên, bạn cần khai báo trạng thái cho dữ liệu nhập của mình, ví dụ this.state = {name: ''} . Thứ hai, bạn cần viết một hàm để thiết lập trạng thái khi nó thay đổi trong ví dụ dưới đây là setName () và cuối cùng bạn phải viết jsx đầu vào, ví dụ <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

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

};

0

sử dụng các trường không được kiểm soát:

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} name="title" />
                ...
            </form>
            ...
            <button type="button" className="btn">Save</button>
            ...
        );
    }

};
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.