2014-09-12 53 views
5

Tôi đã có một thành phần phản ứng với một đầu vào, và một tùy chọn "đầu vào tiên tiến":ReactJs: thay đổi trạng thái để đáp ứng với sự thay đổi trạng thái

[ basic ] 
Hide Advanced... 
[ advanced ] 

Các tiên tiến ở phía dưới sẽ biến mất nếu bạn nhấp vào "Hide Nâng cao ", thay đổi thành" Hiển thị Nâng cao ". Điều đó đơn giản và hoạt động tốt, có một khóa showAdvanced trong trạng thái kiểm soát văn bản và liệu đầu vào nâng cao có được hiển thị hay không. Tuy nhiên,

Mã JS bên ngoài có thể thay đổi giá trị nâng cao, trong trường hợp này tôi muốn hiển thị đầu vào [nâng cao] nếu nó hiện đang bị ẩn và giá trị khác với giá trị mặc định. Tuy nhiên, người dùng có thể nhấp vào "Ẩn nâng cao" để đóng lại.

Vì vậy, ai đó gọi bên ngoài cmp.setState({advanced: "20"}) và sau đó tôi muốn hiển thị nâng cao; Điều đơn giản nhất cần làm là cập nhật showAdvanced ở trạng thái của tôi. Tuy nhiên, dường như không có cách nào để cập nhật một số trạng thái để phản ứng với các thay đổi trạng thái khác trong React. Tôi có thể nghĩ về một số cách giải quyết với hành vi hơi khác nhau, nhưng tôi thực sự muốn có hành vi cụ thể này.

Tôi có nên chuyển showAdvanced sang đạo cụ, điều đó có hợp lý không? Bạn có thể thay đổi đạo cụ để đáp ứng với những thay đổi của tiểu bang không? Cảm ơn.

+0

Đặt một trạng thái tùy thuộc vào trạng thái khác có âm thanh như kiểu chống. Tại sao bạn không chỉ kiểm tra trạng thái 'nâng cao' trong phương thức hiển thị? – David

+0

Bạn có jsfiddle không? Nếu tôi hiểu chính xác, bạn muốn kiểm soát khả năng hiển thị của một phần tử từ bên trong thành phần của bạn, nhưng cũng từ bên ngoài phải không? Vì vậy, tôi sẽ chỉ sử dụng một prop, và có một điều kiện nếu để kiểm tra xem bạn có nên hiển thị nó hay không. –

Trả lời

7

Được rồi, trước tiên, bạn đề cập rằng bên thứ ba bên ngoài thành phần của bạn có thể gọi cmp.setState()? Đây là một phản ứng rất lớn không-không. Một thành phần chỉ nên gọi đó là hàm setState của chính nó - không có gì bên ngoài nên truy cập nó.

Một điều nữa cần nhớ là nếu bạn đang cố gắng thay đổi trạng thái lần nữa để đáp ứng với thay đổi trạng thái - điều đó có nghĩa là bạn đang làm điều gì đó sai.

Khi bạn xây dựng mọi thứ theo cách này, điều này khiến cho vấn đề của bạn khó khăn hơn nhiều so với nhu cầu cần thiết. Lý do là nếu bạn chấp nhận rằng không có gì bên ngoài có thể thiết lập trạng thái của thành phần của bạn - thì về cơ bản lựa chọn duy nhất bạn có là cho phép những thứ bên ngoài cập nhật đạo cụ của thành phần - và sau đó phản ứng với chúng bên trong thành phần của bạn. Điều này đơn giản hóa vấn đề.

Vì vậy, ví dụ bạn nên xem xét có bất cứ điều gì những thứ bên ngoài mà sử dụng để được gọi cmp.setState() thay vì gọi React.renderComponent trên thành phần của bạn một lần nữa, cho một chỗ dựa mới hoặc giá trị prop, chẳng hạn như showAdvanced thiết lập để true. Thành phần của bạn sau đó có thể phản ứng với điều này trong componentWillReceiveProps và đặt trạng thái của nó cho phù hợp.Dưới đây là một ví dụ về mã:

var MyComponent = React.createClass({ 
    getInitialState: function() { 
     return { 
      showAdvanced: this.props.showAdvanced || false 
     } 
    }, 
    componentWillReceiveProps: function(nextProps) { 
     if (typeof nextProps.showAdvanced === 'boolean') { 
      this.setState({ 
       showAdvanced: nextProps.showAdvanced 
      }) 
     } 
    }, 
    toggleAdvancedClickHandler: function(e) { 
     this.setState({ 
      showAdvanced: !this.state.showAdvanced 
     }) 
    }, 
    render: function() { 
     return (
      <div> 
       <div>Basic stuff</div> 
       <div> 
        <button onClick={this.toggleAdvancedClickHandler}> 
         {(this.state.showAdvanced ? 'Hide' : 'Show') + ' Advanced'} 
        </button> 
       </div> 
       <div style={{display: this.state.showAdvanced ? 'block' : 'none'}}> 
        Advanced Stuff 
       </div> 
      </div> 
     ); 
    } 
}); 

Vì vậy, lần đầu tiên bạn gọi React.renderComponent(MyComponent({}), elem) thành phần sẽ gắn kết và div nâng cao sẽ bị ẩn. Nếu bạn bấm vào nút bên trong thành phần, nó sẽ chuyển đổi và hiển thị. Nếu bạn cần ép buộc thành phần hiển thị div tiên tiến từ bên ngoài thành phần, chỉ cần gọi lại hiển thị như sau: React.renderComponent(MyComponent({showAdvanced: true}), elem) và nó sẽ hiển thị nó, bất kể trạng thái nội bộ. Tương tự như vậy nếu bạn muốn ẩn nó từ bên ngoài, chỉ cần gọi nó với showAdvanced: false.

Thêm tiền thưởng vào ví dụ trên là gọi số setState bên trong componentWillReceiveProps không gây ra một chu kỳ hiển thị khác vì nó bắt và thay đổi trạng thái TRƯỚC KHI render được gọi. Hãy nhìn vào các tài liệu vào đây để biết thêm: http://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops

Đừng quên rằng gọi renderComponent một lần nữa vào một bộ phận đã gắn kết không gắn kết nó một lần nữa, nó chỉ nói phản ứng để cập nhật của props thành phần và phản ứng sau đó sẽ làm cho những thay đổi, chạy vòng đời và chức năng render của thành phần và làm phép thuật dom khác biệt của nó.

+0

Cảm ơn, đây chắc chắn là câu trả lời đúng. Tôi đã có một số vấn đề bổ sung (giá trị được thiết lập và đọc bởi thành phần bên ngoài đã được tuần tự hóa/deserialized để phá vỡ các phần nâng cao/cơ bản), nhưng làm mọi thứ thông qua đạo cụ thay vì gọi setState bên ngoài cố định các vấn đề của tôi. – Emoses

0

Câu trả lời được sửa đổi trong nhận xét bên dưới.


ban đầu câu trả lời sai của tôi:

Vòng đời chức năng componentWillUpdate sẽ được chạy khi trạng thái mới hoặc đạo cụ được nhận. Bạn có thể tìm tài liệu về nó ở đây: http://facebook.github.io/react/docs/component-specs.html#updating-componentwillupdate

Nếu, khi bên ngoài setState được gọi, sau đó bạn thiết lập showAdvanced để true trong componentWillUpdate, bạn sẽ nhận được kết quả mong muốn.

CHỈNH SỬA: Một tùy chọn khác là có cuộc gọi bên ngoài tới setState bao gồm showAdvanced: true ở trạng thái mới.

+0

Tài liệu nói rằng bạn không thể sử dụng setState từ bên trong ComponentWillUpdate, đó là lý do tại sao tôi gặp sự cố khi bắt đầu. Tôi nghĩ về việc có giao dịch JS bên ngoài với nhà nước, nhưng điều đó đẩy logic thành phần cụ thể ra cho người tiêu dùng không cần phải đối phó với nó. – Emoses

+0

Ah, đó là sự thật. Bạn có thể muốn 'showAdvanced' có giá trị ban đầu được thiết lập thông qua' props'. Tương tự với 'advanced_text'. Sau đó, nếu một thành phần khác đặt trạng thái 'advanced_text', bạn sẽ sử dụng logic như thế này trong' render': 'this.state.advanced_text || this.props.initial_advanced_text'. Bạn cũng có thể ẩn nút 'Ẩn Nâng cao' nếu' this.state.advanced_text' được đặt. – returneax

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