Sử dụng state hoặc refs trong các thành phần biểu mẫu React.js?


116

Tôi đang bắt đầu với React.js và tôi muốn thực hiện một biểu mẫu đơn giản nhưng trong tài liệu tôi đã tìm thấy hai cách để thực hiện.

Cách đầu tiên đang sử dụng Refs :

var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var author = React.findDOMNode(this.refs.author).value.trim();
    var text = React.findDOMNode(this.refs.text).value.trim();
    if (!text || !author) {
      return;
    }
    // TODO: send request to the server
    React.findDOMNode(this.refs.author).value = '';
    React.findDOMNode(this.refs.text).value = '';
    return;
  },
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

Và cái thứ hai là sử dụng trạng thái bên trong thành phần React:

var TodoTextInput = React.createClass({
  getInitialState: function() {
    return {
      value: this.props.value || ''
    };
  },

  render: function() /*object*/ {
    return (
      <input className={this.props.className}
      id={this.props.id}
      placeholder={this.props.placeholder}
      onBlur={this._save}
      value={this.state.value}
      />
    );
  },

  _save: function() {
    this.props.onSave(this.state.value);
    this.setState({value: ''
  });
});

Tôi không thể thấy ưu và nhược điểm của hai lựa chọn thay thế, nếu một số tồn tại. Cảm ơn.


Am i thiếu cái gì ở đây? Tại sao bạn không sử dụng đối tượng sự kiện để nhận các giá trị biểu mẫu? Đó dường như là lý do duy nhất để sử dụng một biểu mẫu ở đây ngay từ đầu. Nếu bạn không sử dụng hành vi gửi mặc định và có giới thiệu về các đầu vào, bạn không cần phải gói chúng trong một biểu mẫu.
NectarSoft

Câu trả lời:


143

Phiên bản ngắn gọn: tránh giới thiệu.


Chúng không tốt cho khả năng bảo trì và làm mất đi rất nhiều tính đơn giản mà mô hình WYSIWYG cung cấp.

Bạn có một biểu mẫu. Bạn cần thêm một nút đặt lại biểu mẫu.

  • giới thiệu:
    • thao túng DOM
    • kết xuất mô tả biểu mẫu trông như thế nào 3 phút trước
  • tiểu bang
    • setState
    • kết xuất mô tả biểu mẫu trông như thế nào

Bạn có trường số CCV trong đầu vào và một số trường khác trong ứng dụng của bạn là số. Bây giờ bạn cần thực thi người dùng chỉ nhập số.

  • giới thiệu:
    • thêm trình xử lý onChange (không phải chúng ta đang sử dụng refs để tránh điều này sao?)
    • thao tác dom trong onChange nếu nó không phải là một số
  • tiểu bang
    • bạn đã có một trình xử lý onChange
    • thêm câu lệnh if, nếu nó không hợp lệ, không làm gì cả
    • kết xuất chỉ được gọi nếu nó sẽ tạo ra một kết quả khác

Eh, đừng bận tâm, Thủ tướng muốn chúng ta chỉ làm bóng hộp màu đỏ nếu nó không hợp lệ.

  • giới thiệu:
    • làm cho trình xử lý onChange chỉ cần gọi forceUpdate hay gì đó?
    • tạo kết xuất đầu ra dựa trên ... huh?
    • chúng ta lấy giá trị để xác thực trong kết xuất ở đâu?
    • thao tác thủ công thuộc tính className dom của một phần tử?
    • Tôi bị lạc
    • viết lại mà không có refs?
    • đọc từ dom trong kết xuất nếu chúng tôi được gắn kết nếu không, giả sử hợp lệ?
  • tiểu bang:
    • loại bỏ câu lệnh if
    • thực hiện xác thực kết xuất dựa trên this.state

Chúng ta cần trao lại quyền kiểm soát cho phụ huynh. Dữ liệu hiện ở dạng đạo cụ và chúng tôi cần phản ứng với các thay đổi.

  • giới thiệu:
    • triển khai componentDidMount, componentWillUpdate và componentDidUpdate
    • thay đổi thủ công các đạo cụ trước đó
    • thao túng dom với một số thay đổi tối thiểu
    • Chào! chúng tôi đang triển khai phản ứng trong phản ứng ...
    • còn nữa, nhưng ngón tay của tôi bị đau
  • tiểu bang:
    • sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js

Mọi người nghĩ rằng refs 'dễ dàng hơn' so với việc giữ nó ở trạng thái. Điều này có thể đúng trong 20 phút đầu tiên, nó không đúng theo kinh nghiệm của tôi sau đó. Hãy đặt bản thân của bạn vào vị trí để nói "Vâng, tôi sẽ hoàn thành trong 5 phút" thay vì "Chắc chắn rồi, tôi sẽ chỉ viết lại một vài thành phần".


3
Bạn có thể giải thích thêm một chút về sed -e 's / this.state / this.props /' 's / handleChange / onChange /' -i form.js không?
gabrielgiussi

1
Không, ý tôi là những thay đổi thực tế đối với dom. React.findDOMNode(this.refs.foo). Nếu bạn chẳng hạn thay đổi this.refs.foo.props.barsẽ không có gì xảy ra.
Brigand

1
ví dụ: nếu bạn đã <input onChange={this.handleChange} value={this.state.foo} />thay đổi nó thành <input onChange={this.props.handleChange} value={this.props.foo} />, hoặc sửa đổi (các) hàm handleChange của bạn để gọi (các) lệnh gọi lại trong đạo cụ. Dù bằng cách nào, đó là một vài thay đổi nhỏ rõ ràng.
Brigand

4
Không chắc tôi là người duy nhất thấy câu trả lời của bạn hơi khó hiểu. Bạn có thể hiển thị một số mẫu mã làm cho quan điểm của bạn rõ ràng hơn không?
Rishabh

2
Có hơn 50 đầu vào trên màn hình, mỗi đầu vào hiển thị bất kỳ thay đổi trạng thái nào là không mong muốn. Việc cấu thành từng inputtrường trong đó mỗi trường duy trì trạng thái riêng là lý tưởng. Tại một số điểm, chúng ta cần phải điều hòa các trạng thái độc lập khác nhau này với một số mô hình lớn hơn. Có thể chúng ta có chế độ tự động lưu trên bộ đếm thời gian, hoặc chúng ta chỉ tiết kiệm componentWillUnmountĐây là nơi tôi thấy refslý tưởng, trong quá trình điều chỉnh, chúng ta lấy stategiá trị từ mỗi cái refvà không cái nào khôn ngoan hơn. Tôi đồng ý trong hầu hết các trường hợp statelà câu trả lời, nhưng với một số lượng lớn inputs, việc sử dụng một refsmô hình thích hợp là một lợi ích về hiệu suất
lux

105

Tôi đã thấy một vài người trích dẫn câu trả lời ở trên như một lý do để "không bao giờ sử dụng refs" và tôi muốn đưa ra ý kiến ​​của mình (cũng như một số nhà phát triển React khác mà tôi đã nói chuyện).

Ý kiến ​​"không sử dụng refs" là đúng khi nói về việc sử dụng chúng cho các trường hợp thành phần. Có nghĩa là, bạn không nên sử dụng các tham chiếu như một cách để lấy các cá thể thành phần và gọi các phương thức trên chúng. Đây là cách sử dụng ref không chính xác và là khi ref đi nhanh về phía nam.

Cách chính xác (và rất hữu ích) để sử dụng ref là khi bạn đang sử dụng chúng để nhận một số giá trị từ DOM. Ví dụ: nếu bạn có một trường đầu vào gắn một tham chiếu vào đầu vào đó thì việc lấy giá trị sau đó thông qua tham chiếu là tốt. Nếu không có cách này, bạn cần phải trải qua một quy trình được sắp xếp tương đối để giữ cho trường đầu vào của bạn được cập nhật với trạng thái cục bộ hoặc cửa hàng thông lượng của bạn - điều này có vẻ không cần thiết.

Bản chỉnh sửa năm 2019: Xin chào những người bạn của tương lai. Ngoài những gì tôi đã đề cập vài năm trước ^, với React Hooks, refs cũng là một cách tuyệt vời để theo dõi dữ liệu giữa các lần hiển thị và không bị giới hạn ở việc chỉ lấy các nút DOM.


3
Đoạn cuối của bạn có ý nghĩa hoàn hảo, nhưng bạn có thể làm rõ đoạn thứ hai của mình không? Ví dụ cụ thể về việc lấy một cá thể thành phần và gọi một phương thức được coi là không chính xác là gì?
Danny Libin

2
Tôi đồng ý với điều này. Tôi sử dụng refs trừ khi / cho đến khi tôi cần xác thực hoặc thao tác giá trị của một trường. Nếu tôi cần xác thực khi thay đổi hoặc thay đổi các giá trị theo chương trình, thì tôi sử dụng trạng thái.
Christopher Davies

1
Tôi đồng ý với điều này là tốt. Trong giai đoạn khám phá, tôi đã cố tình tiếp cận một màn hình với một số lượng lớn các đầu vào bằng ngây thơ. Tất cả các giá trị đầu vào được lưu trữ trong bản đồ (ở trạng thái) được khóa bởi id. Không cần phải nói, hiệu suất bị ảnh hưởng vì thiết lập trạng thái và hiển thị hơn 50 đầu vào (một số material-ui, rất nặng!) Trên các thay đổi giao diện người dùng nhỏ như một lần nhấp vào hộp kiểm là không lý tưởng. Hợp phần hóa mỗi đầu vào có thể duy trì trạng thái riêng của nó dường như là cách tiếp cận thích hợp. Nếu cần đối chiếu, chỉ cần peer vào refsvà lấy giá trị trạng thái. Nó có vẻ như là một mẫu thực sự đẹp.
lux

2
Tôi hoàn toàn đồng ý. Câu trả lời được chấp nhận là quá mơ hồ theo quan điểm của tôi.
James Wright

Tôi đồng ý. Trong khi thiết kế một thành phần Biểu mẫu chung, điều này làm sáng tỏ những điểm khó khăn của các thành phần được kiểm soát và quản lý tiêu điểm, xử lý lỗi, v.v. Không thể có một kiến ​​trúc sạch trên thực tế. Nói chuyện với tôi nếu được yêu cầu. Tôi đang chuyển các thành phần của mình sang refs.
kushalvm

6

TL; DR Nói chung, refsđi ngược lại triết lý khai báo của React , vì vậy bạn nên sử dụng chúng như một phương sách cuối cùng. Sử dụng state / propsbất cứ khi nào có thể.


Để hiểu nơi bạn sử dụng refsvs state / props, hãy xem xét một số nguyên tắc thiết kế mà React tuân theo.

Tài liệu Per React vềrefs

Tránh sử dụng refs cho bất kỳ thứ gì có thể được thực hiện một cách khai báo.

Nguyên tắc thiết kế của Per React về Escape Hatch

Nếu một số mẫu hữu ích cho việc xây dựng ứng dụng khó diễn đạt theo cách khai báo, chúng tôi sẽ cung cấp một API bắt buộc cho nó. (và họ liên kết đến giới thiệu ở đây)

Có nghĩa là nhóm của React đề xuất nên tránh refsvà sử dụng state / propscho bất kỳ điều gì có thể được thực hiện theo cách phản ứng / khai báo.

@Tyler McGinnis đã đưa ra một câu trả lời rất hay , cũng nêu rõ rằng

Cách chính xác (và rất hữu ích) để sử dụng ref là khi bạn đang sử dụng chúng để nhận một số giá trị từ DOM ...

Mặc dù bạn có thể làm được điều đó, nhưng bạn sẽ làm việc chống lại triết lý của React. Nếu bạn có giá trị trong một đầu vào, nó chắc chắn đến từ state / props. Để giữ cho mã nhất quán và có thể dự đoán được, bạn cũng nên tuân theo điều state / propsđó. Tôi thừa nhận thực tế là refsđôi khi mang lại cho bạn giải pháp nhanh hơn, vì vậy nếu bạn làm một bằng chứng về khái niệm, nhanh và bẩn là chấp nhận được.

Điều này để lại cho chúng tôi một số trường hợp sử dụng cụ thể chorefs

Quản lý tiêu điểm, lựa chọn văn bản hoặc phát lại phương tiện. Kích hoạt hoạt ảnh bắt buộc. Tích hợp với thư viện DOM của bên thứ ba.


5

Bài đăng này đã cũ.

Tôi sẽ chia sẻ kinh nghiệm nhỏ của tôi về một trường hợp về vấn đề đó.

Tôi đang làm việc trên một thành phần lớn (414 dòng) với rất nhiều đầu vào 'động' và nhiều dữ liệu được lưu trong bộ nhớ cache liên quan. (Tôi không làm việc một mình trên trang và các giác quan của tôi cho tôi biết rằng cấu trúc của mã có thể có thể được phân tách tốt hơn, nhưng đó không phải là vấn đề (tốt, có thể là vậy nhưng tôi đang xử lý nó)

Lần đầu tiên tôi làm việc với trạng thái để xử lý các giá trị của đầu vào:

  const [inputsValues, setInputsValues] = useState([])
  const setInputValue = (id, value) => {
    const arr = [...inputsValues]
    arr[id] = value
    setInputsValues(arr)
  }

và tất nhiên trong các đầu vào:

value={inputsValues[id] || ''}
onChange={event => setInputValue(id, event.target.value)}

Kết xuất quá nặng khiến thay đổi đầu vào bị thay đổi như **** (đừng cố giữ phím, văn bản sẽ chỉ xuất hiện sau khi tạm dừng)

Tôi chắc chắn rằng tôi có thể tránh điều này bằng cách sử dụng refs.

đã kết thúc như thế này:

  const inputsRef = useRef([])

và trong các đầu vào:

ref={input => (inputsRef.current[id] = input)}

[tốt trong trường hợp của tôi Đầu vào là Trường văn bản Material-UI nên nó là:

inputRef={input => (inputsRef.current[id] = input)}

]

Nhờ đó, không có kết xuất, đầu vào mượt mà, tính vui nhộn hoạt động theo cùng một cách. Nó sẽ tiết kiệm chu kỳ và tính toán, do đó năng lượng cũng vậy. Làm điều đó cho trái đất x)

Kết luận của tôi: useRef cho giá trị đầu vào thậm chí có thể cần thiết.

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.