Làm cách nào để truy cập phần tử DOM trong React? Điểm cân bằng của document.getEuityById () trong React là gì


202

Làm cách nào để chọn một số thanh nhất định trong Reac.js?

Đây là mã của tôi:

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

Tôi muốn sử dụng thành phần React này:

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

Tôi muốn thực thi chức năng handleClick10 và thực hiện thao tác cho thanh tiến trình đã chọn của mình. Nhưng kết quả tôi nhận được là:

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

Làm cách nào để chọn Phần tử nhất định trong Reac.js?

Câu trả lời:


213

Bạn có thể làm điều đó bằng cách chỉ định ref

EDIT: Trong phản ứng v16.8.0 với thành phần chức năng, bạn có thể định nghĩa một ref với useRef. Lưu ý rằng khi bạn chỉ định một tham chiếu cho một thành phần chức năng, bạn cần sử dụng React.forwardRef trên nó để chuyển tiếp tham chiếu đến phần tử DOM sử dụng useImperativeHandleđể hiển thị một số chức năng từ bên trong thành phần chức năng

Ví dụ:

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

BIÊN TẬP:

Trong React 16.3+ , sử dụng React.createRef()để tạo ref của bạn:

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

Để truy cập phần tử, sử dụng:

const node = this.myRef.current;

DOC để sử dụng React.createRef ()


BIÊN TẬP

Tuy nhiên, facebook khuyên chống lại nó bởi vì giới thiệu chuỗi có một số vấn đề, được coi là di sản và có khả năng sẽ bị xóa trong một trong những bản phát hành trong tương lai.

Từ các tài liệu:

API kế thừa: Tham chiếu chuỗi

Nếu bạn đã làm việc với React trước đó, bạn có thể quen với một API cũ hơn trong đó thuộc tính ref là một chuỗi, như "textInput" và nút DOM được truy cập như this.refs.textInput. Chúng tôi khuyên bạn nên chống lại nó bởi vì giới thiệu chuỗi có một số vấn đề, được coi là di sản và có khả năng sẽ bị xóa trong một trong các phiên bản tương lai. Nếu bạn hiện đang sử dụng this.refs.textInput để truy cập ref, chúng tôi khuyên bạn nên sử dụng mẫu gọi lại.

Một cách được đề xuất cho React 16.2 trở về trước là sử dụng mẫu gọi lại:

<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 để sử dụng gọi lại


Ngay cả các phiên bản cũ hơn của phản ứng được xác định sử dụng chuỗi như dưới đây

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

Để có được yếu tố chỉ cần làm

var object = this.refs.Progress1;

Hãy nhớ sử dụng thisbên trong một khối chức năng mũi tên như:

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

và như thế...


5
Facebook khuyên chống lại phương pháp này. Xem tại đây facebook.github.io/react/docs/refs-and-the-dom.html
Dmitry

4
@dmitrymar Như tôi có thể thấy trang trên được viết cho v15.4.2 trở đi và tôi đoán, điều này không có ở đó sớm hơn khi tôi viết câu trả lời. Dù sao cũng đã chỉnh sửa câu trả lời với cách tiếp cận đúng
Shubham Khatri

2
@MattSidor, cảm ơn vì đã chỉnh sửa, bạn đã tiết kiệm cho tôi một chút thời gian :-)
Shubham Khatri

Ừm, câu hỏi là gì nếu tôi không thể truy cập nó thông qua "cái này", như thế nào nếu thành phần tôi cần là một thể hiện của một lớp khác? (tức là một đứa trẻ khác phản ứng thành phần trong thành phần cha mẹ)
akshay kishore

@akshaykishore Bạn sẽ cần chuyển ref bằng cách sử dụng tên khác là InternalRef và chuyển nó đến thành phần mong muốn
Shubham Khatri

37

Để có được phần tử trong reactbạn cần sử dụng refvà bên trong hàm bạn có thể sử dụng ReactDOM.findDOMNodephương thức.

Nhưng những gì tôi muốn làm nhiều hơn là gọi cho ref ngay trong sự kiện

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

Đây là một số liên kết tốt để giúp bạn tìm ra.


2
Đây là cách chính xác để làm điều này. Điều này thêm một tham chiếu đến phần tử trên đối tượng / lớp mà bạn có thể chỉ cần sử dụng this.myTextInputđể truy cập.
Sam Parmenter

1
Làm thế nào tôi có thể làm điều này với phần tử được tạo động?
Sagar Kodte

Gọi React.findDOMNodecho tôireact__WEBPACK_IMPORTED_MODULE_0___default.a.findDOMNode is not a function
James Poulose

@JamesPoulose đảm bảo bạn không chạy ở chế độ nghiêm ngặt, vì phản ứng sẽ không cho phép bạn sử dụng React.findDOMNodeở chế độ nghiêm ngặt.
Limpuls

12

Bạn có thể thay thế

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

với

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


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

3
Làm thế nào tôi có thể làm điều này với phần tử được tạo động?
Sagar Kodte

1

Vì React sử dụng mã JSX để tạo HTML, chúng tôi không thể tham chiếu dom bằng các phương thức quy định như documment.querySelector hoặc getEuityById.

Thay vào đó, chúng ta có thể sử dụng hệ thống ref React để truy cập và thao tác với Dom như trong ví dụ dưới đây:

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
Đây không phải là sự thật. Bạn có thể thêm id vào phần tử img, lấy nó bằng document.getEuityById và trong hầu hết các trường hợp, nó sẽ hoạt động tốt. Nó có thể gây ra sự cố / làm cho mã của bạn khó gỡ lỗi hơn, nhưng phản ứng / jsx donlt làm cho nó để bạn CANT sử dụng các phương thức Dom gốc
adam tropp
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.