Как получить доступ к элементу DOM в React? Что эквивалентно document.getElementById () в React

205

Как выбрать определенные бары в Reaction.js?

Это мой код:

var Progressbar = React.createClass({
    getInitialState: function () {
        return { completed: this.props.completed };
    },
    addPrecent: function (value) {
        this.props.completed += value;
        this.setState({ completed: this.props.completed });
    },

    render: function () {

        var completed = this.props.completed;
        if (completed < 0) { completed = 0 };


        return (...);
    }

Я хочу использовать этот компонент React:

var App = React.createClass({
    getInitialState: function () {

        return { baction: 'Progress1' };
    },
    handleChange: function (e) {
        var value = e.target.value;
        console.log(value);
        this.setState({ baction: value });
    },
    handleClick10: function (e) {
        console.log('You clicked: ', this.state.baction);
        document.getElementById(this.state.baction).addPrecent(10);
    },
    render: function () {
        return (
            <div class="center">Progress Bars Demo
            <Progressbar completed={25} id="Progress1" />
                <h2 class="center"></h2>
                <Progressbar completed={50} id="Progress2" />
                <h2 class="center"></h2>
                <Progressbar completed={75} id="Progress3" />
                <h2 class="center"></h2>
                <span>
                    <select name='selectbar' id='selectbar' value={this.state.baction} onChange={this.handleChange}>
                        <option value="Progress1">#Progress1</option>
                        <option value="Progress2">#Progress2</option>
                        <option value="Progress3">#Progress3</option>
                    </select>
                    <input type="button" onClick={this.handleClick10} value="+10" />
                    <button>+25</button>
                    <button>-10</button>
                    <button>-25</button>
                </span>
            </div>
        )
    }
});

Я хочу выполнить функцию handleClick10 и выполнить операцию для моего выбранного индикатора выполнения. Но результат, который я получаю:

 You clicked:  Progress1
 TypeError: document.getElementById(...) is null

Как мне выбрать определенный элемент вact.js?

user504909
источник

Ответы:

215

Вы можете сделать это, указав ref

РЕДАКТИРОВАТЬ: В реакции v16.8.0 с функциональным компонентом вы можете определить ссылку с помощью useRef. Обратите внимание, что когда вы указываете ref для функционального компонента, вам нужно использовать React.forwardRef для него, чтобы перенаправить ref в элемент использования DOM, useImperativeHandleчтобы показать некоторые функции из функционального компонента.

Пример:

const Child1 = React.forwardRef((props, ref) => {
    return <div ref={ref}>Child1</div> 
});

const Child2 = React.forwardRef((props, ref) => {
    const handleClick= () =>{};
    useImperativeHandle(ref,() => ({
       handleClick
    }))
    return <div>Child2</div> 
});
const App = () => {
    const child1 = useRef(null);
    const child2 = useRef(null);

    return (
        <>
           <Child1 ref={child1} />
           <Child1 ref={child1} />
        </>
    )
}

РЕДАКТИРОВАТЬ:

В React 16.3+ используйте React.createRef()для создания вашего ref:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}

Для доступа к элементу используйте:

const node = this.myRef.current;

DOC для использования React.createRef ()


РЕДАКТИРОВАТЬ

Однако facebook советует против этого, потому что ссылки на строки имеют некоторые проблемы, считаются устаревшими и, вероятно, будут удалены в одном из будущих выпусков.

Из документов:

Устаревший API: Строковые ссылки

Если вы работали с React ранее, вы, возможно, знакомы с более старым API, в котором атрибут ref является строкой, такой как «textInput», а узел DOM доступен как this.refs.textInput. Мы не рекомендуем этого делать, потому что у строковых ссылок есть некоторые проблемы, они считаются устаревшими и, вероятно, будут удалены в одном из будущих выпусков. Если вы в настоящее время используете this.refs.textInput для доступа к ссылкам, мы рекомендуем вместо этого использовать шаблон обратного вызова.

Рекомендуемый способ для React 16.2 и более ранних версий - использовать шаблон обратного вызова:

<Progressbar completed={25} id="Progress1" ref={(input) => {this.Progress[0] = input }}/>

<h2 class="center"></h2>

<Progressbar completed={50} id="Progress2" ref={(input) => {this.Progress[1] = input }}/>

  <h2 class="center"></h2>

<Progressbar completed={75} id="Progress3" ref={(input) => {this.Progress[2] = input }}/>

DOC для использования обратного вызова


Даже более старые версии реагируют на определенные ссылки, используя строку, как показано ниже

<Progressbar completed={25} id="Progress1" ref="Progress1"/>

    <h2 class="center"></h2>

    <Progressbar completed={50} id="Progress2" ref="Progress2"/>

      <h2 class="center"></h2>

    <Progressbar completed={75} id="Progress3" ref="Progress3"/>

Чтобы получить элемент, просто сделайте

var object = this.refs.Progress1;

Не забудьте использовать thisвнутри функционального блока стрелки, как:

print = () => {
  var object = this.refs.Progress1;  
}

и так далее...

Шубхам Хатри
источник
5
Facebook советует против такого подхода. Смотрите здесь facebook.github.io/react/docs/refs-and-the-dom.html
Дмитрий
4
@dmitrymar Как я вижу выше, эта страница написана для v15.4.2 и далее, и я думаю, этого не было раньше, когда я писал ответ. Anyways отредактировал ответ с правильным подходом
Shubham Khatri
2
@MattSidor, спасибо за редактирование, вы сэкономили мне время :-)
Шубхам Хатри
Хм, вопрос, что если я не могу получить к нему доступ через "this", например, что, если нужный мне компонент является экземпляром другого класса? (т.е. другой дочерний компонент реагирует в родительском компоненте)
akshay kishore
@akshaykishore Вам нужно было бы передать реф, используя другое имя, скажем, innerRef, и передать его нужному компоненту
Шубхам Хатри,
37

Для получения элемента reactвам нужно использовать refи внутри функции вы можете использовать ReactDOM.findDOMNodeметод.

Но то, что мне нравится делать больше, это вызывать реф прямо на мероприятии

<input type="text" ref={ref => this.myTextInput = ref} />

Это хорошая ссылка, которая поможет вам разобраться.

EQuimper
источник
2
Это правильный способ сделать это. Это добавляет ссылку на элемент объекта / класса, который вы можете просто использовать this.myTextInputдля доступа.
Сэм Парментер
1
Как я могу сделать это с динамически созданным элементом?
Сагар Кодте
Звонок React.findDOMNodeдает мнеreact__WEBPACK_IMPORTED_MODULE_0___default.a.findDOMNode is not a function
Джеймс Poulose
@JamesPoulose убедитесь, что вы не работаете в строгом режиме, потому что реакция не позволит вам использовать React.findDOMNodeв строгом режиме.
Лимпульс
13

Вы можете заменить

document.getElementById(this.state.baction).addPrecent(10);

с участием

this.refs[this.state.baction].addPrecent(10);


  <Progressbar completed={25} ref="Progress1" id="Progress1"/>
Piyush.kapoor
источник
3
Как я могу сделать это с динамически созданным элементом?
Сагар Кодте
1

Поскольку React использует код JSX для создания HTML, мы не можем ссылаться на dom, используя методы регулирования, такие как documment.querySelector или getElementById.

Вместо этого мы можем использовать систему React ref для доступа и управления Dom, как показано в следующем примере:

constructor(props){

    super(props);
    this.imageRef = React.createRef(); // create react ref
}

componentDidMount(){

    **console.log(this.imageRef)** // acessing the attributes of img tag when dom loads
}


render = (props) => {

const {urls,description} = this.props.image;
    return (

            <img
             **ref = {this.imageRef} // assign the ref of img tag here**
             src = {urls.regular} 
             alt = {description}
             />

        );

}

}

Нихил Камани
источник
1
Это неправда. Вы можете добавить идентификатор к элементу img, захватить его, используя document.getElementById, и в большинстве случаев он будет работать нормально. Это может вызвать проблемы / усложнить отладку вашего кода, но реакция / jsx не делает это так, что вы НЕ МОЖЕТЕ использовать нативные методы Dom
Адам Тропп