在 React 中使用 refs 有什么不好的做法?

What's a bad practice with refs in React?

我开始学习 React。不同站点的一些人告诉每个人使用 refs 是一种不好的做法(是的,根本不使用它们)。

它的真正含义是什么?我将它附加到子组件(以便我可以访问内部内容)是不是很糟糕?

谢谢!

React 要求您 think the react way 并且 refs 是您几乎不需要使用的 DOM 的后门。为了彻底简化,React 的思维方式是,一旦状态发生变化,您就重新渲染 all 依赖于该状态的 UI 组件。 React 将负责确保只更新 DOM 的正确位,使整个事情变得高效并向你隐藏 DOM(有点)。

例如,如果您的组件托管 HTMLInputElement,则在 React 中您将连接一个事件处理程序来跟踪对输入元素的更改。每当用户键入一个字符时,事件处理程序就会触发,在您的处理程序中,您将使用输入元素的新值更新您的状态。状态更改会触发托管组件重新呈现自身,包括具有新值的输入元素。

这就是我的意思

import React from 'react';
import ReactDOM from 'react-dom';

class Example extends React.Component {

    state = {
      inputValue: ""
    }

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

    render() {
        const { inputValue } = this.state
        return ( 
          <div>
            /**.. lots of awesome ui **/
            /** an input element **/
            <input value={inputValue} onChange={this.handleChange}} />
            /** ... some more awesome ui **/
          </div>
       )
  }
}


ReactDOM.render( <Example />, document.getElementById("app") );
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>


<div id="app">
</div>

注意输入值何时更改、处理程序如何被调用、setState 被调用以及组件将完全重新呈现自身。

考虑 refs 通常是一种不好的做法,因为你可能会想只使用 refs 并按照 JQuery 的方式做事,这不是 React architecture/mindset 的意图。

真正更好地理解它的最好方法是构建更多的 React 应用程序和组件。

嗯...不确定它是否符合回答的条件,但它变得太长而无法发表评论。

假设您有一个仪表板,其中包含显示系统各种状态的小部件。每个小部件都有自己的数据源和自己的控件。也许他们甚至不时刷新。但是,当用户想要查看系统的更新视图时,在仪表板级别有一个 "Refresh" 按钮。实现这样一个按钮并不简单。

如果您在 Redux 应用程序中 - 您可以选择 - "faking" dispatch('refresh') 所有子项。为了分离它,每个小部件在加载时注册一个动作,以便父级简单地完成所有动作并在需要 强制性 刷新时触发它们。

在非 Redux/Flux 系统中,或者在更多 complex/dynamic 场景中,这可能是不可能的,或者可能不是那么简单。 然后可能更好,复杂性明智,在所有小部件上公开 refresh 方法,然后从父级(或者更确切地说,所有者)访问它:

class WidgetA extends React.Component {
    refresh() {
        console.log('WidgetA refreshed');
    }

    render() {
      return (
        <h3>WidgetA</h3>
      );
    }
}  

class WidgetB extends React.Component {
    refresh() {
        console.log('WidgetB refreshed');
    }

    render() {
      return (
        <h3>WidgetB</h3>
      );
    }
}  

class Dashboard extends React.Component {
    constructor() {
        super();

        this.onRefresh = this.handleRefresh.bind(this);
        this.onRegister = this.handleRegister.bind(this);
        this.widgets = [];
    }

    handleRegister(widget) {
        this.widgets.push(widget);
    }

    handleRefresh() {
        this.widgets.forEach((widget) => {
            widget.refresh();
        });
    }

    render() {
        return (
            <div>
                <button onClick={this.onRefresh}>Refresh</button>
                <hr />
                <WidgetA ref={this.onRegister} />
                <WidgetB ref={this.onRegister} />
            </div>
        );
    }
}

类似的东西,当然不那么冗长。

As side note, I upvoted @skav answer and think that these scenarios should be avoided. This is an exception.

CodePen Example