Javascript 如何将引用分配给多个组件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47055464/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 03:43:08  来源:igfitidea点击:

How to assign refs to multiple components

javascriptreactjs

提问by Valip

I'm using React to render multiple data using array.map.
How can disable the clicked button from the list?

我正在使用 React 来渲染多个数据array.map
如何从列表中禁用单击的按钮?

This is my code:

这是我的代码:

  onRunClick(act, e) {
    this.refs.btn.setAttribute("disabled", true);
  }

  render () {
    return (
      <div>
        {
          this.state.acts.map((act) => {
            let boundActRunClick = this.onRunClick.bind(this, act);

            return (
              <p key={act._id}>
                Name: {act.name}, URL(s): {act.urls}
                <button ref='btn' onClick={boundActRunClick}>Run</button>
              </p>
            )
          })
        }
      </div>
    );
  }
}

Using refsdoesn't work ... I think that I can't add a state since there are multiple buttons.

使用refs不起作用......我认为我无法添加状态,因为有多个按钮。

采纳答案by Shubham Khatri

You should use ref callbackinstead of ref and also yes you need multiple refs, an array should be good

你应该使用ref callback而不是 ref 并且是的你需要多个 refs,一个数组应该是好的

According to the docs:

根据文档:

React supports a special attribute that you can attach to any component. The ref attribute takes a callbackfunction, and the callbackwill be executed immediately after the component is mounted or unmounted.

When the ref attribute is used on an HTML element, the ref callbackreceives the underlying DOM element as its argument.

ref callbacksare invoked before componentDidMountor componentDidUpdatelifecycle hooks.

Using the ref callback just to set a property on the class is a common pattern for accessing DOM elements. The preferred way is to set the property in the ref callback like in the above example. There is even a shorter way to write it: ref={input => this.textInput = input}.

React 支持可以附加到任何组件的特殊属性。ref 属性带有一个callback函数, callback在组件挂载或卸载后会立即执行。

当 ref 属性用于 HTML 元素时,它ref callback接收底层 DOM 元素作为其参数。

ref callbackscomponentDidMountcomponentDidUpdate生命周期钩子之前调用。

使用 ref 回调只是在类上设置属性是访问 DOM 元素的常见模式。首选方法是在 ref 回调中设置属性,如上例所示。甚至还有一种更短的写法:ref={input => this.textInput = input}.

String refs are a legacy and and as per the docs:

字符串引用是遗留的,并且根据文档

Legacy API: String Refs

旧 API:字符串引用

If you worked with React before, you might be familiar with an older API where the ref attribute is a string, like "textInput", and the DOM node is accessed as this.refs.textInput. We advise against it because string refs have some issues, are considered legacy, and are likely to be removed in one of the future releases. If you're currently using this.refs.textInputto access refs, we recommend the callback pattern instead.

如果您之前使用过 React,您可能熟悉一个旧的 API,其中 ref 属性是一个字符串,如“textInput”,并且 DOM 节点作为this.refs.textInput. 我们建议不要这样做,因为字符串引用有一些问题,被认为是遗留的,并且可能会在未来的版本之一中被删除。如果您当前正在使用this.refs.textInput访问refs,我们建议改为使用回调模式。

constructor() {
    super();
    this.btn = [];
}
onRunClick(act, index, e) {
    this.btn[index].setAttribute("disabled", true);
  }

  render () {
    return (
      <div>
        {
          this.state.acts.map((act, index) => {
            let boundActRunClick = this.onRunClick.bind(this, act, index);

            return (
              <p key={act._id}>
                Name: {act.name}, URL(s): {act.urls}
                <button ref={(ref) => this.btn[index] = ref} onClick={boundActRunClick}>Run</button>
              </p>
            )
          })
        }
      </div>
    );
  }

回答by bennygenel

Like @ShubhamKhatri's answer using refis an option. You can also achieve desired behavior with state too.

就像@ShubhamKhatri 的回答一样,使用ref是一种选择。您也可以通过状态实现所需的行为。

Example(Single Disabled Button Option)

示例(单个禁用按钮选项)

class App extends Component{
  constructor() {
    super();
    this.state = {
      disabled: ''
    };
  }

  onRunClick(act, index, e) {
    this.setState({ disabled: act._id });
  }

  render() {
    return (
      <div>
        {
          this.state.acts.map((act, index) => {
            let boundActRunClick = this.onRunClick.bind(this, act, index);
            return (
              <p key={act._id}>
                Name: {act.name}, URL(s): {act.urls}
                <button disabled={this.state.disabled === act._id} onClick={boundActRunClick}>Run</button>
              </p>
            )
          })
        }
      </div>
    );
  }
}

Example(Multiple Disabled Button Option)

示例(多个禁用按钮选项)

class App extends Component{
  constructor() {
    super();
    this.state = {
      buttons: {}
    };
  }

  onRunClick(act, index, e) {
    this.setState((prevState) => { 
      const buttons = Object.assign({}, prevState.buttons, { [act._id]: !prevState.buttons[act._id] });
      return { buttons };
    });
  }

  render() {
    return (
      <div>
        {
          this.state.acts.map((act, index) => {
            let boundActRunClick = this.onRunClick.bind(this, act, index);
            return (
              <p key={act._id}>
                Name: {act.name}, URL(s): {act.urls}
                <button disabled={this.state.buttons[act._id] || false} onClick={boundActRunClick}>Run</button>
              </p>
            )
          })
        }
      </div>
    );
  }
}

回答by Macil

You can use the npm module react-multi-ref(a tiny library by me) to do this.

您可以使用 npm 模块react-multi-ref(我的一个小库)来做到这一点。

import React from 'react';
import MultiRef from 'react-multi-ref';

class Foo extends React.Component {
  _actRefs = new MultiRef();

  onRunClick(act, e) {
    this._actRefs.map.get(act._id).setAttribute("disabled", true);
  }

  render () {
    return (
      <div>
        {
          this.state.acts.map((act) => {
            let boundActRunClick = this.onRunClick.bind(this, act);

            return (
              <p key={act._id}>
                Name: {act.name}, URL(s): {act.urls}
                <button ref={this._actRefs.ref(act._id)} onClick={boundActRunClick}>Run</button>
              </p>
            )
          })
        }
      </div>
    );
  }
}

Though in this specific case where you just want to change an attribute on an element, instead of using a ref you should do it through state and props on the <button>through React as in the answer by @bennygenel. But if you need to do something else (call an imperative DOM method on the button, read the value of an uncontrolled input element, read the screen position of an element, etc) then you'll need to use a ref like this.

尽管在这种特定情况下,您只想更改元素上的属性,而不是使用 ref,您应该<button>通过 React上的 state 和 props 来完成,如@bennygenel 的回答所示。但是,如果您需要做其他事情(在按钮上调用命令式 DOM 方法、读取不受控制的输入元素的值、读取元素的屏幕位置等),那么您将需要使用这样的 ref。

回答by ZCaceres

For function components (React 16+), you can approach it like the following:

对于函数组件(React 16+),你可以像下面这样处理它:

/* 
 * @param {Object|Function} forwardedRef callback ref function  or ref object that `refToAssign` will be assigned to
 * @param {Object} refToAssign React ref object
 */
export function assignForwardedRefs(forwardedRef, refToAssign) {
  if (forwardedRef) {
    if (typeof forwardedRef === 'function') {
      forwardedRef(refToAssign)
    } else {
      forwardedRef.current = refToAssign
    }
  }
}


function MyComponent({
  forwardedRef
}) {
   const innerRef = useRef()

   function setRef(ref) {
     assignForwardedRefs(forwardedRef, ref)
     innerRef.current = ref
   }

   return <div ref={setRef}>Hello World!</div>
}

export default React.forwardRef((props, ref) => <MyComponent {...props} forwardedRef={ref} />)