2015-02-27 18 views
18

Tôi gặp sự cố này khi xây dựng một ứng dụng web và tôi đã sao chép nó trong số jsfiddle này. Về cơ bản, tôi muốn một đầu vào để gọi this.setState({message: input_val}) mỗi khi tôi nhập một cái gì đó vào nó, sau đó vượt qua nó vào lớp App cha sau đó lại ám thông điệp vào lớp Message. Tuy nhiên đầu ra dường như luôn luôn là một bước phía sau những gì tôi thực sự gõ. Bản demo jsfiddle nên tự giải thích. Tôi tự hỏi nếu tôi đã làm bất cứ điều gì sai để nhắc điều này.Biểu mẫu phản hồi onChange-> setState một bước sau

html

<script src="http://facebook.github.io/react/js/jsfiddle-integration.js"></script> 
<div id='app'></div> 

js

var App = React.createClass({ 
    getInitialState: function() { 
     return {message: ''} 
    }, 
    appHandleSubmit: function(state) { 
     this.setState({message: state.message}); 
     console.log(this.state.message); 
    }, 
    render: function() { 
     return (
      <div className='myApp'> 
      <MyForm onChange={this.appHandleSubmit}/> 
      <Message message={this.state.message}/> 
      </div> 
     ); 
    } 
}); 

var MyForm = React.createClass({ 
    handleSubmit: function() { 
     this.props.onChange(this.state); 
    }, 
    handleChange: function(e) { 
     console.log(e.target.value); 
     this.setState({message: e.target.value}); 
     this.handleSubmit(); 
    }, 
    render: function() { 
     return (
      <form className="reactForm" onChange={this.handleChange}> 
      <input type='text' /> 
      </form> 
     ); 
    } 
}); 

var Message = React.createClass({ 
    render: function() { 
     return (
      <div className="message"> 
       <p>{this.props.message}</p> 
      </div> 
     ) 
    } 
}); 

React.render(
    <App />, 
    document.getElementById('app') 
); 

Trả lời

24

Một cuộc gọi đến setState là không đồng bộ. Nó tạo ra "trạng thái chuyển tiếp đang chờ xử lý". (Xem here để biết thêm chi tiết). Bạn nên chuyển giá trị input mới một cách rõ ràng như một phần của sự kiện đang được nêu lên (ví dụ như handleSubmit trong ví dụ của bạn).

Xem ví dụ this.

handleSubmit: function(txt) { 
    this.props.onChange(txt); 
}, 
handleChange: function(e) { 
    var value = e.target.value; 
    this.setState({message: value}); 
    this.handleSubmit(value); 
}, 
+0

bạn thưa ông xứng đáng danh tiếng 41K của bạn! –

4

Không có lý do gì để MyForm sử dụng trạng thái tại đây. Cũng đặt onChange trên form thay vì input mà bạn quan tâm là odd. Các thành phần được kiểm soát nên được ưu tiên hơn vì hành vi của chúng rõ ràng hơn và bất kỳ lúc nào trạng thái thông báo của ứng dụng (ngay cả khi bạn cho phép Tin nhắn thay đổi sau), nó sẽ chính xác ở mọi nơi.

Điều này cũng làm cho mã của bạn ngắn hơn một chút và đơn giản hơn đáng kể.

var App = React.createClass({ 
    getInitialState: function() { 
     return {message: ''} 
    }, 
    appHandleSubmit: function(message) { 
     this.setState({message: message}); 
    }, 
    render: function() { 
     return (
      <div className='myApp'> 
       <MyForm onChange={this.appHandleSubmit} 
         message={this.state.message} /> 
       <Message message={this.state.message}/> 
      </div> 
     ); 
    } 
}); 

var MyForm = React.createClass({ 
    handleInputChange: function(e){ 
     this.props.onChange(e.target.value); 
    }, 
    // now always in sync with the parent's state 
    render: function() { 
     return (
      <form className="reactForm"> 
       <input type='text' onChange={this.handleInputChange} 
         value={this.props.message} /> 
      </form> 
     ); 
    } 
}); 

jsbin

+0

Cảm ơn các refactor, tôi đã nghiên cứu mã của bạn và lấy một số điểm tốt từ nó. Có vẻ như sử dụng this.props là một ý tưởng tốt cho các khung nhìn thuần túy, và sử dụng this.state là tốt cho các bộ điều khiển. –

+0

Chủ yếu là có.Thỉnh thoảng có một cái gì đó giống như một trình đơn thả xuống, nơi trạng thái mở/đóng có thể được giữ riêng tư cho thành phần (tại sao bạn lại quan tâm nếu trình đơn thả xuống được mở trong bố mẹ?). Đôi khi các thành phần giao diện người dùng cũng cần phải theo dõi một số thứ như vị trí con trỏ và sử dụng nó trong kết xuất, để kết thúc ở trạng thái cục bộ của chúng. – FakeRainBrigand

+0

FYI - mã này không hoạt động như cũ. 'onChange' không truyền văn bản thực tế của hộp nhập vào như một giá trị như bạn đã thực hiện ở đó (một' SyntheticEvent' thực sự được truyền đi). Tôi cũng sẽ không mong đợi rằng một container nên biết bất cứ điều gì về các chi tiết cụ thể về cách một thành phần con được trả lại, vì vậy nó không nên sử dụng 'e.target.value' để lấy giá trị từ hộp nhập liệu. Đó là lý do tại sao có một mức độ vô hướng là rất hữu ích trong một cái gì đó như 'MyForm' trong mã ban đầu. – WiredPrairie

0

tôi thấy nó rất cồng kềnh đối với tôi để xác định 3 chức năng xử lý chỉ để có được một số giá trị cho tình trạng của một thành phần, vì vậy tôi đã quyết định không sử dụng nhà nước ở tất cả. Tôi chỉ định nghĩa một thuộc tính bổ sung cho thành phần lưu trữ giá trị mong muốn.

Vì vậy, tôi đã kết thúc với một mã mà nhìn một cái gì đó như thế này:

//... 
}, 
text: '', 
handleChange: function(event) { 
    this.text = event.target.value; 
    this.forceUpdate(); 
}, 
render: function() { 
    return <div> 
     <InputComponent onChange={this.handleChange}/> 
     <DisplayComponent textToDisplay={this.text}/> 
     </div> 
} 
//... 
9

Có một cách đơn giản hơn nhiều để làm điều này,

Đơn giản chỉ cần vượt qua handleSubmit như một callback để setstate phương pháp, theo cách này sau khi setState hoàn thành chỉ handleSubmit sẽ được thực hiện.

Ví dụ:

handleChange: function(e) { 
    console.log(e.target.value); 
    this.setState({message: e.target.value}, this.handleSubmit); 
} 

Cố gắng thay đổi phương thức handleChange() như ở trên và nó sẽ hoạt động.

cho cú pháp của việc sử dụng setstate việc kiểm tra này link

+0

+1 Đây là câu trả lời hợp lý nhất mà tôi nghĩ. Bạn có thể đã đề cập đến thay thế với componentDidUpdate quá;) – Kjellski

Các vấn đề liên quan