Como acessar um elemento DOM no React? Qual é o equilíbrio de document.getElementById () em React

203

Como seleciono determinadas barras no react.js?

Este é o meu código:

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 (...);
    }

Eu quero usar este componente 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>
        )
    }
});

Quero executar a função handleClick10 e executar a operação para minha barra de progresso selecionada. Mas o resultado que recebo é:

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

Como seleciono o elemento certo em react.js?

user504909
fonte

Respostas:

214

Você pode fazer isso especificando o ref

EDIT: No react v16.8.0 com componente funcional, você pode definir uma ref com useRef. Observe que, quando você especifica uma ref em um componente funcional, é necessário usar React.forwardRef para encaminhar a ref para o elemento DOM usado useImperativeHandlepara expor determinadas funções de dentro do componente funcional

Ex:

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} />
        </>
    )
}

EDITAR:

No React 16.3+ , use React.createRef()para criar sua referência:

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

Para acessar o elemento, use:

const node = this.myRef.current;

DOC para usar React.createRef ()


EDITAR

No entanto, o Facebook desaconselha, pois os refs de string têm alguns problemas, são considerados herdados e provavelmente serão removidos em uma das versões futuras.

Dos documentos:

API herdada: referências de sequência

Se você trabalhou com o React antes, pode estar familiarizado com uma API mais antiga, na qual o atributo ref é uma sequência, como "textInput", e o nó DOM é acessado como this.refs.textInput. Aconselhamo-lo, porque os refs de string têm alguns problemas, são considerados herdados e provavelmente serão removidos em uma das versões futuras. Se você estiver usando this.refs.textInput para acessar refs, recomendamos o padrão de retorno de chamada.

Uma maneira recomendada para o React 16.2 e versões anteriores é usar o padrão de retorno de chamada:

<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 para usar retorno de chamada


Mesmo versões mais antigas de reações definidas refs usando string como abaixo

<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"/>

Para obter o elemento basta fazer

var object = this.refs.Progress1;

Lembre-se de usar thisdentro de um bloco de funções de seta como:

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

e assim por diante...

Shubham Khatri
fonte
5
O Facebook desaconselha essa abordagem. Veja aqui facebook.github.io/react/docs/refs-and-the-dom.html
Dmitry
4
@dmitrymar Como posso ver, a página acima foi escrita para a v15.4.2 em diante e acho que isso não existia antes quando escrevi a resposta. De qualquer forma editado a resposta com a abordagem correta
Shubham Khatri
2
@MattSidor, obrigado pela edição, você me salvou algum tempo :-)
Shubham Khatri
Hum, questione e se eu não puder acessá-lo através do "this", como se o componente que eu preciso for uma instância de outra classe? (ou seja, uma outra criança reagir componente dentro do componente pai)
akshay Kishore
@akshaykishore Você precisaria passar o árbitro para baixo, usando outro nome diz innerRef e passá-lo ao componente desejado
Shubham Khatri
37

Para obter o elemento, reactvocê precisa usar refe dentro da função, você pode usar o ReactDOM.findDOMNodemétodo

Mas o que eu mais gosto de chamar é o árbitro dentro do evento

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

Este é um bom link para ajudá-lo a descobrir.

EQuimper
fonte
2
Esta é a maneira correta de fazer isso. Isso adiciona uma referência ao elemento no objeto / classe ao qual você pode simplesmente usar this.myTextInputpara acessar.
Sam Parmenter
1
Como posso fazer isso com o elemento criado dinamicamente?
Sagar Kodte 17/09/19
Chamar React.findDOMNodeme dáreact__WEBPACK_IMPORTED_MODULE_0___default.a.findDOMNode is not a function
James Poulose 23/02
@JamesPoulose verifique se você não está executando no modo estrito, porque reagir não permitirá que você use React.findDOMNodeno modo estrito.
Limpuls
12

Você pode substituir

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

com

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


  <Progressbar completed={25} ref="Progress1" id="Progress1"/>
Piyush.kapoor
fonte
3
Como posso fazer isso com o elemento criado dinamicamente?
Sagar Kodte 17/09/19
1

Como o React usa o código JSX para criar um HTML, não podemos nos referir a métodos de regulação como documment.querySelector ou getElementById.

Em vez disso, podemos usar o sistema React ref para acessar e manipular o Dom, como mostrado no exemplo abaixo:

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}
             />

        );

}

}

Nikhil Kamani
fonte
1
Isso não é verdade. Você pode adicionar um ID ao elemento img, obtê-lo usando document.getElementById e, na maioria dos casos, ele funcionará bem. Isso pode causar problemas / tornar seu código mais difícil de depurar, mas react / jsx donlt o tornam para que você não possa usar métodos
nat