Jak uzyskać dostęp do elementu DOM w React? Jaka jest równowaga document.getElementById () w React

203

Jak wybrać określone paski w pliku reag.js?

To jest mój kod:

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

Chcę użyć tego komponentu 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>
        )
    }
});

Chcę uruchomić funkcję handleClick10 i wykonać operację dla wybranego paska postępu. Ale wynik to:

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

Jak wybrać określony element w React.js?

użytkownik504909
źródło

Odpowiedzi:

214

Możesz to zrobić, określając ref

EDYCJA: W reakcji v16.8.0 ze składnikiem funkcjonalnym można zdefiniować ref za pomocą useRef. Zauważ, że kiedy określasz ref dla komponentu funkcjonalnego, musisz użyć React.forwardRef, aby przekazać ref do elementu DOM używanego useImperativeHandlew celu ujawnienia niektórych funkcji z komponentu funkcjonalnego

Dawny:

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

EDYTOWAĆ:

W React 16.3+ użyj, React.createRef()aby utworzyć swój ref:

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

Aby uzyskać dostęp do elementu, użyj:

const node = this.myRef.current;

DOC za używanie React.createRef ()


EDYTOWAĆ

Jednak Facebook odradza to, ponieważ referencje ciągów mają pewne problemy, są uważane za starsze i prawdopodobnie zostaną usunięte w jednym z przyszłych wydań.

Z dokumentów:

Legacy API: String Refs

Jeśli pracowałeś wcześniej z React, możesz znać starszy interfejs API, w którym atrybut ref jest ciągiem, takim jak „textInput”, a dostęp do węzła DOM można uzyskać jako this.refs.textInput. Odradzamy to, ponieważ referencje ciągów mają pewne problemy, są uważane za starsze i prawdopodobnie zostaną usunięte w jednym z przyszłych wydań. Jeśli obecnie używasz this.refs.textInput w celu uzyskania dostępu do referencji, zalecamy zamiast tego wzorzec wywołania zwrotnego.

Zalecanym sposobem dla React 16.2 i wcześniejszych jest użycie wzorca wywołania zwrotnego:

<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 za korzystanie z oddzwaniania


Nawet starsze wersje reagujących zdefiniowanych referencji przy użyciu łańcucha jak poniżej

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

Aby uzyskać element, po prostu zrób

var object = this.refs.Progress1;

Pamiętaj, aby używać thiswewnątrz bloku funkcyjnego strzałki, takiego jak:

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

i tak dalej...

Shubham Khatri
źródło
5
Facebook odradza takie podejście. Zobacz tutaj facebook.github.io/react/docs/refs-and-the-dom.html
Dmitry
4
@dmitrymar Jak widzę, powyższa strona jest napisana dla wersji 15.4.2 i, jak sądzę, nie było jej wcześniej, kiedy napisałem odpowiedź. W każdym razie zredagował odpowiedź z prawidłowym podejściem
Shubham Khatri
2
@MattSidor, dzięki za edycję, zaoszczędziłeś mi trochę czasu :-)
Shubham Khatri
Um, pytaj co jeśli nie mogę uzyskać do niego dostępu poprzez „to”, na przykład co jeśli komponent, którego potrzebuję, jest instancją innej klasy? (tj. inny element reagujący podrzędnie w ramach elementu nadrzędnego)
akshay kishore
@akshaykishore Trzeba by przekazać referencję używając innej nazwy, powiedz innerRef i przekazać ją do pożądanego komponentu
Shubham Khatri
37

Aby wprowadzić element react, musisz użyć, refa wewnątrz funkcji możesz użyć ReactDOM.findDOMNodemetody.

Ale to, co lubię robić, to zadzwonić do sędziego bezpośrednio w trakcie wydarzenia

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

To jest dobry link, który pomoże ci zrozumieć.

EQuimper
źródło
2
To jest właściwy sposób, aby to zrobić. Dodaje to odwołanie do elementu w obiekcie / klasie, do którego można po prostu użyć w this.myTextInputcelu uzyskania dostępu.
Sam Parmenter,
1
Jak mogę to zrobić za pomocą dynamicznie tworzonego elementu?
Sagar Kodte
Dzwonienie React.findDOMNodedaje mireact__WEBPACK_IMPORTED_MODULE_0___default.a.findDOMNode is not a function
James Poulose
@JamesPoulose upewnij się, że nie pracujesz w trybie ścisłym, ponieważ reakcja nie pozwoli ci na użycie React.findDOMNodew trybie ścisłym.
Limpuls
12

Możesz wymienić

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

z

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


  <Progressbar completed={25} ref="Progress1" id="Progress1"/>
Piyush.kapoor
źródło
3
Jak mogę to zrobić za pomocą dynamicznie tworzonego elementu?
Sagar Kodte
1

Ponieważ React używa kodu JSX do utworzenia HTML, nie możemy polecać domeny przy użyciu metod regulacji, takich jak documment.querySelector lub getElementById.

Zamiast tego możemy użyć systemu referencyjnego React, aby uzyskać dostęp do Dom i manipulować nim, jak pokazano w poniższym przykładzie:

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
źródło
1
To nie jest prawda. Możesz dodać identyfikator do elementu img, pobrać go za pomocą document.getElementById, a w większości przypadków będzie działać dobrze. Może to powodować problemy / utrudnić debugowanie kodu, ale zareaguj / jsx donlt sprawia, że ​​NIE MOŻESZ używać natywnych metod Dom
adam tropp