Panggil metode komponen React dari luar

95

Saya ingin memanggil metode yang diekspos oleh komponen React dari instance Elemen React.

Misalnya, di jsfiddle ini . Saya ingin memanggil alertMessagemetode dari HelloElementreferensi.

Adakah cara untuk mencapai ini tanpa harus menulis pembungkus tambahan?

Edit (kode disalin dari 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')
);
Prajurit Kaya
sumber
3
Tidak ideal, tetapi JSFiddle cukup umum sehingga tidak menjamin penurunan suara.
Jeff Fairley
Saya bertanya-tanya apa yang bisa menjadi kasus penggunaan Anda yang akan menjamin hal seperti itu. Ini bukan cara yang baik untuk mendesain imo aplikasi Anda. Jika Anda memang perlu menggunakan kembali sesuatu, buatlah alat bantu umum terpisah di file ketiga dan gunakan untuk tombol Anda serta komponen react Anda.
rasa teh

Jawaban:

56

Ada dua cara untuk mengakses fungsi batin. Satu, tingkat instance, seperti yang Anda inginkan, yang lainnya, tingkat statis.

Contoh

Anda perlu memanggil fungsi saat kembali dari React.render. Lihat di bawah.

Statis

Lihat ReactJS Statics . Perhatikan, bagaimanapun, bahwa fungsi statis tidak dapat mengakses data tingkat instance, begitu thisjuga 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'));

Lalu lakukan HelloRendered.alertMessage().

Jeff Fairley
sumber
13
Perhatikan bahwa menggunakan nilai hasil render dianggap sudah usang, dan diharapkan akan dihapus di versi mendatang untuk mengaktifkan peningkatan kinerja. Cara yang didukung untuk mendapatkan referensi ke objek instance komponen Anda adalah dengan menambahkan properti refyang merupakan fungsi yang dipanggil dengan instance sebagai parameter. Ini juga memungkinkan Anda untuk mengakses objek yang tidak berada di tingkat atas, misalnya jika Anda sedang merender, <MuiThemeProvider><Hello ref={setHelloRef} /></MuiThemeProvider>Anda mendapatkan referensi yang tepat yang diteruskan ke setHelloReffungsi Anda daripada satu ke MuiThemeProvider.
Periata Breatta
TypeError Tidak Tertangkap: _react2.default.render bukan fungsi
Partha Paul
46

Anda bisa melakukan seperti

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;

Nah dari luar komponen ini Anda bisa memanggil seperti ini di bawah ini

window.helloComponent.alertMessage();
Kushal Jain
sumber
2
Nyatanya, sederhana dan fungsional! Seperti yang seharusnya. Saya sangat terkesan dengan betapa sederhananya itu; benar-benar tidak terpikirkan. Mungkin pendekatan ini tidak akan bekerja sebaik itu jika ada lebih banyak komponen yang seharusnya. Terima kasih!
Leonardo Maffei
6
Menambahkan variabel global bukanlah solusi yang baik. Lebih lanjut tentang mengapa variabel global buruk di sini: wiki.c2.com/?GlobalVariablesAreBad
Salvatore Zappalà
4
Terima kasih atas suaranya !! Ya variabel global tidak bagus tapi itulah cara untuk menyelesaikan masalah Anda.
Kushal Jain
1
Ini adalah solusi pragmatis dan sederhana yang saya butuhkan, terima kasih!
Florent Destremau
2
itu berhasil tetapi tidak akan berfungsi jika Anda memiliki beberapa komponen yang sama di halaman yang sama.
gaurav
26

Saya telah melakukan sesuatu seperti ini:

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

}

Dan kemudian di tempat lain:

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

}

Saya belum menguji kode persis ini, tetapi ini sejalan dengan apa yang saya lakukan dalam proyek saya dan berfungsi dengan baik :). Tentu saja ini adalah contoh yang buruk, Anda hanya perlu menggunakan props untuk ini, tetapi dalam kasus saya sub-komponen melakukan panggilan API yang ingin saya simpan di dalam komponen itu. Dalam kasus seperti ini, ini adalah solusi yang bagus.

gitaarik
sumber
5
Saya pikir yang Anda maksudthis.cowCallbacks.say('moo')
Steven
BTW dimungkinkan untuk meneruskan thiske callback (yang akan menjadi turunan Sapi) sebagai ganti callbacks.
WebBrother
@WebBrother Ya, tapi itu akan menjadi lebih
hacky
6

Dengan rendermetode yang berpotensi menghentikan nilai yang dikembalikan, pendekatan yang disarankan sekarang adalah memasang callback ref ke elemen root. Seperti ini:

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

yang kemudian dapat kita akses menggunakan window.helloComponent, dan metodenya dapat diakses dengan window.helloComponent.METHOD.

Berikut contoh lengkapnya:

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>

Brett DeWoody
sumber
Lebih baik meletakkan referensi di negara bagian lokal daripada di objek jendela ... ref={component => {this.setState({ helloComponent: component; })}} Kemudian, di click handler ... this.state.helloComponent.alertMessage();
Bill Dagg
Selanjutnya ke komentar saya sebelumnya ... atau, lebih baik lagi, cukup letakkan metode alertMessage komponen dalam status.
Bill Dagg
Ketika saya mencoba ini, saya mendapatkan Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?dan tidak mengikat komponen ke jendela
Gerilya
4
class AppProvider extends Component {
  constructor() {
    super();

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

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

Anda dapat memanggil metode ini dari jendela dengan menggunakan window.alertMessage().

Mygel Bergstresser
sumber
Ini akan berhasil tetapi menambahkan variabel global bukanlah solusi yang baik, karena berbagai alasan. Anda dapat menemukan info lebih lanjut tentang mengapa variabel global buruk di sini: wiki.c2.com/?GlobalVariablesAreBad
Salvatore Zappalà
3

Jika Anda menggunakan ES6, cukup gunakan kata kunci "statis" pada metode Anda dari contoh Anda adalah sebagai berikut: static alertMessage: function() { ...
},

Semoga bisa membantu siapa saja di luar sana :)

darmis
sumber
Anda tidak dapat menjangkau alat peraga atau status dalam fungsi statis.
Serdar Değirmenci
Oke ya, tapi pertanyaannya adalah tentang mengakses fungsi alertMessage () sehingga Anda bisa menggunakan HelloElement.alertMessage ().
darmis
Umumnya memanggil suatu fungsi tanpa menggunakan props dan state tidak berpengaruh. Tetapi karena Anda benar tentang mencapai fungsi, saya menghapus suara saya
Serdar Değirmenci
3

Dengan 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.current.handleClick}>
        Additional Button
      </button>
    </>
  )
}

Semoga berhasil...

Aakash
sumber
2

Anda bisa menambahkan onClickhandler ke div dengan fungsi ( onClickadalah implementasi React sendiri onClick) dan Anda bisa mengakses properti di dalam { }kurung kurawal, dan pesan peringatan Anda akan muncul.

Jika Anda ingin mendefinisikan metode statis yang bisa dipanggil pada kelas komponen - Anda harus menggunakan statika. Meskipun:

"Metode yang ditentukan dalam blok ini bersifat statis, artinya Anda dapat menjalankannya sebelum instance komponen apa pun dibuat, dan metode tersebut tidak memiliki akses ke props atau status komponen Anda. Jika Anda ingin memeriksa nilai props secara statis metode, minta pemanggil meneruskan props sebagai argumen ke metode statis. " ( sumber )

Beberapa kode contoh:

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

Semoga ini sedikit membantu Anda, karena saya tidak tahu apakah saya memahami pertanyaan Anda dengan benar, jadi perbaiki saya jika saya salah menafsirkannya :)

Danillo Felixdaal
sumber
2

metode 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>

Metode 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>
Mohideen bin Mohammed
sumber
metode 1 adalah cara yang sangat mudah dan bersih untuk mengakses metode komponen anak. Terima kasih!
gabdara
1

Saya menggunakan metode helper ini untuk membuat komponen dan mengembalikan contoh komponen. Metode dapat dipanggil pada contoh itu.

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