Gọi một phương thức thành phần React từ bên ngoài


95

Tôi muốn gọi một phương thức được hiển thị bởi một thành phần React từ phiên bản của Phần tử React.

Ví dụ, trong jsfiddle này . Tôi muốn gọi alertMessagephương thức từ HelloElementtham chiếu.

Có cách nào để đạt được điều này mà không cần phải viết thêm các trình bao bọc không?

Chỉnh sửa (mã đã sao chép từ JSFiddle)

<div id="container"></div>
<button onclick="onButtonClick()">Click me!</button>
var onButtonClick = function () {

    //call alertMessage method from the reference of a React Element! Something like HelloElement.alertMessage()
    console.log("clicked!");
}

var Hello = React.createClass({displayName: 'Hello',

    alertMessage: function() {
        alert(this.props.name);                             
    },

    render: function() {
        return React.createElement("div", null, "Hello ", this.props.name);
    }
});

var HelloElement = React.createElement(Hello, {name: "World"});

React.render(
    HelloElement,
    document.getElementById('container')
);

3
Không lý tưởng, nhưng JSFiddle đủ phổ biến để nó không đảm bảo một cuộc bỏ phiếu từ chối.
Jeff Fairley,

Tôi tự hỏi điều gì có thể là trường hợp sử dụng của bạn sẽ đảm bảo một điều như vậy. Đây không phải là một cách tốt để thiết kế imo ứng dụng của bạn. Nếu bạn cần sử dụng lại thứ gì đó, hãy tạo một trình trợ giúp chung riêng trong tệp thứ ba và sử dụng nó cho nút cũng như thành phần phản ứng của bạn.
trà có hương vị vào

Câu trả lời:


56

Có hai cách để truy cập một hàm bên trong. Một, mức cá thể, như bạn muốn, một, mức tĩnh.

Phiên bản

Bạn cần gọi hàm khi trả về từ React.render. Xem bên dưới.

Tĩnh

Hãy xem ReactJS Statics . Tuy nhiên, lưu ý rằng một hàm tĩnh không thể truy cập dữ liệu mức cá thể, điều thisnày cũng xảy ra undefined.

var onButtonClick = function () {
    //call alertMessage method from the reference of a React Element! 
    HelloRendered.alertMessage();
    //call static alertMessage method from the reference of a React Class! 
    Hello.alertMessage();
    console.log("clicked!");
}

var Hello = React.createClass({
    displayName: 'Hello',
    statics: {
        alertMessage: function () {
            alert('static message');
        }
    },
    alertMessage: function () {
        alert(this.props.name);
    },

    render: function () {
        return React.createElement("div", null, "Hello ", this.props.name);
    }
});

var HelloElement = React.createElement(Hello, {
    name: "World"
});

var HelloRendered = React.render(HelloElement, document.getElementById('container'));

Sau đó làm HelloRendered.alertMessage().


13
Lưu ý rằng việc sử dụng giá trị trả về của kết xuất được coi là không được dùng nữa và dự kiến ​​sẽ bị loại bỏ trong các phiên bản sau để cho phép cải thiện hiệu suất. Cách được hỗ trợ để nhận tham chiếu đến đối tượng cá thể thành phần của bạn là thêm một thuộc tính reflà một hàm được gọi với thể hiện dưới dạng tham số. Điều này cũng cho phép bạn truy cập các đối tượng không ở cấp cao nhất, ví dụ: nếu bạn đang hiển thị, <MuiThemeProvider><Hello ref={setHelloRef} /></MuiThemeProvider>bạn sẽ nhận được tham chiếu phù hợp được chuyển đến setHelloRefhàm của mình thay vì một tham chiếu tới MuiThemeProvider.
Periata Breatta vào

45

Bạn có thể làm như

import React from 'react';

class Header extends React.Component{

    constructor(){
        super();
        window.helloComponent = this;
    }

    alertMessage(){
       console.log("Called from outside");
    }

    render(){

      return (
      <AppBar style={{background:'#000'}}>
        Hello
      </AppBar>
      )
    }
}

export default Header;

Bây giờ từ bên ngoài thành phần này, bạn có thể gọi như thế này bên dưới

window.helloComponent.alertMessage();

1
Trong thực tế, đơn giản và chức năng! Giống như nó được cho là phải. Tôi rất ấn tượng với cách nó đơn giản; thực sự không nghĩ đến. Có thể cách tiếp cận này sẽ không hoạt động tốt nếu có ngày càng nhiều thành phần bạn nên làm. Cảm ơn bạn!
Leonardo Maffei

6
Thêm một biến toàn cục không phải là một giải pháp tốt. Thông tin thêm về lý do tại sao các biến toàn cục là xấu ở đây: wiki.c2.com/?GlobalVariablesAreBad
Salvatore Zappalà

3
Cảm ơn đã bỏ phiếu xuống !! Có biến toàn cục không tốt nhưng đó là một cách để giải quyết vấn đề của bạn.
Kushal Jain

Đây chính xác là giải pháp thực dụng và đơn giản mà tôi cần, cảm ơn!
Florent Destremau

2
nó hoạt động nhưng nó sẽ không hoạt động nếu bạn có nhiều thành phần giống nhau trên cùng một trang.
gaurav

26

Tôi đã làm một việc như thế này:

class Cow extends React.Component {

    constructor (props) {
        super(props);
        this.state = {text: 'hello'};
    }

    componentDidMount () {
        if (this.props.onMounted) {
            this.props.onMounted({
                say: text => this.say(text)
            });
        }
    }

    render () {
        return (
            <pre>
                 ___________________
                < {this.state.text} >
                 -------------------
                        \   ^__^
                         \  (oo)\_______
                            (__)\       )\/\
                                ||----w |
                                ||     ||
            </pre>
        );
    }

    say (text) {
        this.setState({text: text});
    }

}

Và sau đó ở một nơi khác:

class Pasture extends React.Component {

    render () {
        return (
            <div>
                <Cow onMounted={callbacks => this.cowMounted(callbacks)} />
                <button onClick={() => this.changeCow()} />
            </div>
        );
    }

    cowMounted (callbacks) {
        this.cowCallbacks = callbacks;
    }

    changeCow () {
        this.cowCallbacks.say('moo');
    }

}

Tôi chưa kiểm tra mã chính xác này, nhưng đây là dòng của những gì tôi đã làm trong một dự án của tôi và nó hoạt động tốt :). Tất nhiên đây là một ví dụ tồi, bạn chỉ nên sử dụng các đạo cụ cho việc này, nhưng trong trường hợp của tôi, thành phần phụ đã thực hiện một lệnh gọi API mà tôi muốn giữ bên trong thành phần đó. Trong trường hợp này, đây là một giải pháp tốt.


5
Tôi nghĩ rằng bạn có nghĩa làthis.cowCallbacks.say('moo')
Steven

BTW có thể chuyển thistới callback (sẽ là một thể hiện của Cow) thay vì callbacks.
WebBrother

@WebBrother Có, nhưng đó sẽ là thậm chí hacky hơn
gitaarik

6

Với renderphương thức có khả năng không chấp nhận giá trị trả về, phương pháp được đề xuất bây giờ là đính kèm một tham chiếu gọi lại vào phần tử gốc. Như thế này:

ReactDOM.render( <Hello name="World" ref={(element) => {window.helloComponent = element}}/>, document.getElementById('container'));

mà sau đó chúng ta có thể truy cập bằng window.helloComponent và bất kỳ phương thức nào của nó cũng có thể được truy cập bằng window.helloComponent.METHOD.

Đây là một ví dụ đầy đủ:

var onButtonClick = function() {
  window.helloComponent.alertMessage();
}

class Hello extends React.Component {
  alertMessage() {
    alert(this.props.name);
  }

  render() {
    return React.createElement("div", null, "Hello ", this.props.name);
  }
};

ReactDOM.render( <Hello name="World" ref={(element) => {window.helloComponent = element}}/>, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>
<button onclick="onButtonClick()">Click me!</button>


Tốt hơn để đưa các tài liệu tham khảo trong tình trạng địa phương thay vì trên các đối tượng cửa sổ ... ref={component => {this.setState({ helloComponent: component; })}} Sau đó, trong xử lý nhấp chuột ... this.state.helloComponent.alertMessage();
Bill Dagg

Ngoài nhận xét trước đây của tôi ... hoặc tốt hơn, chỉ cần đặt phương thức alertMessage của thành phần vào trạng thái.
Bill Dagg

Khi tôi thử điều này, tôi nhận được Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?và nó không liên kết thành phần với cửa sổ
Guerrilla

4
class AppProvider extends Component {
  constructor() {
    super();

    window.alertMessage = this.alertMessage.bind(this);
  }

  alertMessage() {
    console.log('Hello World');
 }
}

Bạn có thể gọi phương thức này từ cửa sổ bằng cách sử dụng window.alertMessage().


Điều này sẽ hiệu quả nhưng việc thêm một biến toàn cục không phải là một giải pháp tốt, vì nhiều lý do. Bạn có thể tìm thêm thông tin về lý do tại sao các biến toàn cục là xấu ở đây: wiki.c2.com/?GlobalVariablesAreBad
Salvatore Zappalà

3

Nếu bạn đang ở ES6, chỉ cần sử dụng từ khóa "static" trên phương thức của bạn từ ví dụ của bạn sẽ như sau: static alertMessage: function() { ...
},

Hy vọng có thể giúp bất cứ ai ngoài đó :)


Bạn không thể tiếp cận các đạo cụ hoặc trạng thái trong một hàm tĩnh.
Serdar Değirmenci

Ok có, nhưng câu hỏi là về việc truy cập hàm alertMessage () để bạn có thể sử dụng HelloElement.alertMessage ().
darmis

Nói chung gọi một hàm mà không sử dụng đạo cụ và trạng thái không có tác dụng. Nhưng khi bạn là đúng về đạt chức năng, tôi bỏ phiếu bầu của tôi
Serdar Değirmenci

2

Bạn chỉ có thể thêm một onClicktrình xử lý vào div bằng hàm ( onClicklà triển khai riêng của React onClick) và bạn có thể truy cập thuộc tính trong { }dấu ngoặc nhọn và thông báo cảnh báo của bạn sẽ xuất hiện.

Trong trường hợp bạn muốn xác định các phương thức tĩnh có thể được gọi trên lớp thành phần - bạn nên sử dụng phương thức tĩnh. Mặc du:

"Các phương thức được định nghĩa trong khối này là tĩnh, nghĩa là bạn có thể chạy chúng trước khi tạo bất kỳ phiên bản thành phần nào và các phương thức này không có quyền truy cập vào đạo cụ hoặc trạng thái của các thành phần của bạn. Nếu bạn muốn kiểm tra giá trị của đạo cụ trong trạng thái tĩnh , yêu cầu người gọi chuyển vào trong props làm đối số cho phương thức tĩnh. " ( nguồn )

Một số mã ví dụ:

    const Hello = React.createClass({

        /*
            The statics object allows you to define static methods that can be called on the component class. For example:
        */
        statics: {
            customMethod: function(foo) {
              return foo === 'bar';
            }
        },


        alertMessage: function() {
            alert(this.props.name);                             
        },

        render: function () {
            return (
                <div onClick={this.alertMessage}>
                Hello {this.props.name}
                </div>
            );
        }
    });

    React.render(<Hello name={'aworld'} />, document.body);

Hy vọng điều này sẽ giúp bạn một chút, bởi vì tôi không biết liệu tôi có hiểu câu hỏi của bạn đúng không, vì vậy hãy sửa cho tôi nếu tôi diễn giải sai :)



2

phương pháp 1 using ChildRef :

public childRef: any = React.createRef<Hello>();

public onButtonClick= () => {
    console.log(this.childRef.current); // this will have your child reference
}

<Hello ref = { this.childRef }/>
<button onclick="onButtonClick()">Click me!</button>

Phương pháp 2: using window register

public onButtonClick= () => {
    console.log(window.yourRef); // this will have your child reference
}

<Hello ref = { (ref) => {window.yourRef = ref} }/>`
<button onclick="onButtonClick()">Click me!</button>

phương pháp 1 là một cách rất dễ dàng và sạch sẽ để truy cập các phương thức thành phần con. cảm ơn!
gabdara

2

Với React hook - useRef



const MyComponent = ({myRef}) => {
  const handleClick = () => alert('hello world')
  myRef.current.handleClick = handleClick
  return (<button onClick={handleClick}>Original Button</button>)
}

MyComponent.defaultProps = {
  myRef: {current: {}}
}

const MyParentComponent = () => {
  const myRef = React.useRef({})
  return (
    <>
      <MyComponent 
        myRef={myRef}
      />
      <button onClick={myRef.curent.handleClick}>
        Additional Button
      </button>
    </>
  )
}

Chúc may mắn...


1

Tôi sử dụng phương thức trợ giúp này để kết xuất các thành phần và trả về một thể hiện thành phần. Các phương thức có thể được gọi trên trường hợp đó.

static async renderComponentAt(componentClass, props, parentElementId){
         let componentId = props.id;
        if(!componentId){
            throw Error('Component has no id property. Please include id:"...xyz..." to component properties.');
        }

        let parentElement = document.getElementById(parentElementId);

        return await new Promise((resolve, reject) => {
            props.ref = (component)=>{
                resolve(component);
            };
            let element = React.createElement(componentClass, props, null);
            ReactDOM.render(element, parentElement);
        });
    }
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.