Dışarıdan bir React bileşen yöntemi çağırın


95

Bir React Element örneğinden bir React bileşeni tarafından gösterilen bir yöntemi çağırmak istiyorum.

Örneğin, bu jsfiddle'da . alertMessageYöntemi HelloElementreferanstan çağırmak istiyorum .

Ek paketler yazmak zorunda kalmadan bunu başarmanın bir yolu var mı?

Düzenle (JSFiddle'dan kod kopyalandı)

<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
İdeal değil, ancak JSFiddle, olumsuz oylamayı gerektirmeyecek kadar yaygındır.
Jeff Fairley

Böyle bir şeyi garanti edecek kullanım durumunuz ne olabilir merak ediyorum. Bu, uygulama imo'nuzu tasarlamak için iyi bir yol değildir. Bir şeyi yeniden kullanmanız gerekiyorsa, lütfen üçüncü bir dosyada ayrı bir ortak yardımcı oluşturun ve bunu düğmeniz ve tepki bileşeniniz için kullanın.
teaflavored

Yanıtlar:


56

Bir iç işleve erişmenin iki yolu vardır. İstediğiniz gibi bir örnek düzeyi, başka bir statik düzey.

Örnek

Dönüşte işlevi çağırmanız gerekir React.render . Aşağıya bakınız.

Statik

ReactJS Statics'e bir göz atın . Bununla birlikte, statik bir işlev değil erişim örneği düzeyindeki veriler, bu nedenle ki thisolacaktır 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'));

O zaman yap HelloRendered.alertMessage().


13
Oluşturmanın dönüş değerini kullanmanın kullanımdan kaldırıldığını ve performans geliştirmelerini sağlamak için gelecekteki sürümlerde kaldırılmasının beklendiğini unutmayın. Bileşen örneği nesnenize bir başvuru almanın desteklenen yolu ref, örnekle parametre olarak çağrılan bir işlev olan bir özellik eklemektir . Bu aynı zamanda en üst seviyede olmayan nesnelere erişmenize de olanak tanır, örneğin, eğer render <MuiThemeProvider><Hello ref={setHelloRef} /></MuiThemeProvider>ediyorsanız, setHelloReffonksiyonunuza bir yerine doğru referansı alırsınız MuiThemeProvider.
Periata Breatta

Yakalanmamış TypeError: _react2.default.render bir işlev değil
Partha Paul

46

Beğenebilirsin

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;

Şimdi bu bileşenin dışından aşağıdaki gibi arayabilirsin

window.helloComponent.alertMessage();

2
Aslında basit ve işlevsel! Olması gerektiği gibi. Bu kadar basit olmasından çok etkilendim; gerçekten düşünmedim. Yapmanız gereken daha fazla bileşen varsa, muhtemelen bu yaklaşım o kadar iyi çalışmayacaktır. Teşekkür ederim!
Leonardo Maffei

6
Global bir değişken eklemek iyi bir çözüm değildir. Küresel değişkenlerin neden kötü olduğuna dair daha fazla bilgiyi
Salvatore Zappalà

4
Olumsuz oy için teşekkürler !! Evet, küresel değişken iyi değil ama bu, probleminizi çözmenin bir yoludur.
Kushal Jain

1
Bu tam da ihtiyacım olan pragmatik ve basit çözüm, teşekkürler!
Florent Destremau

2
işe yaradı, ancak aynı sayfada birden fazla aynı bileşene sahipseniz çalışmaz.
gaurav

26

Bunun gibi bir şey yaptım:

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

}

Ve sonra başka bir yerde:

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

}

Bu kodu tam olarak test etmedim, ancak bu benim bir projemde yaptığım şey doğrultusunda ve güzel çalışıyor :). Elbette bu kötü bir örnek, bunun için sadece props kullanmalısınız, ancak benim durumumda alt bileşen, o bileşenin içinde tutmak istediğim bir API çağrısı yaptı. Böyle bir durumda bu güzel bir çözüm.


5
Sanırım şunu demek this.cowCallbacks.say('moo')
Steven

BTW yerine thisgeri aramaya (Cow'ın bir örneği olacak) geçmek mümkündür callbacks.
WebBrother

@WebBrother Evet, ama bu daha da zor olabilir
gitaarik

6

İle renderyöntem potansiyel olarak dönen değeri küçümseyen, tavsiye edilen yaklaşım kök elemana bir geri arama ref eklemek şimdi. Bunun gibi:

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

daha sonra window.helloComponent kullanarak erişebiliriz ve yöntemlerinden herhangi birine window.helloComponent.METHOD ile erişilebilir.

İşte tam bir örnek:

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>


Referansı pencere nesnesi yerine yerel duruma koymak daha ref={component => {this.setState({ helloComponent: component; })}}this.state.helloComponent.alertMessage();
iyidir

Önceki yorumuma ek olarak ... veya daha iyisi, bileşenin alertMessage yöntemini duruma getirin.
Bill Dagg 18-19

Bunu denediğimde elde ederim Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?ve bileşeni pencereye bağlamaz
Gerilla

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

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

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

Bu yöntemi kullanarak pencereden çağırabilirsiniz window.alertMessage().


Bu işe yarayabilir, ancak birçok nedenden ötürü global bir değişken eklemek iyi bir çözüm değildir. Global değişkenlerin neden kötü olduğuna dair daha fazla bilgiyi burada bulabilirsiniz: wiki.c2.com/?GlobalVariablesAreBad
Salvatore Zappalà

3

ES6 içindeyseniz, yönteminizdeki örneğinizdeki "statik" anahtar kelimesini kullanın: static alertMessage: function() { ...
},

Umut oradaki herkese yardım edebilir :)


Statik bir işlevde sahne veya duruma erişemezsiniz.
Serdar Değirmenci

Tamam evet, ancak soru alertMessage () işlevine erişmek üzereydi, böylece HelloElement.alertMessage () kullanabilirsiniz.
darmis

Genellikle props ve state kullanmadan bir işlevi çağırmanın bir etkisi yoktur. Ancak işleve ulaşma konusunda haklı olduğunuz için oyumu kaldırıyorum
Serdar Değirmenci

3

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

İyi şanslar...


2

onClickFonksiyonla onClickdiv'e bir işleyici ekleyebilirsiniz ( React'in kendi uygulamasıdır onClick) ve özelliğe içinden erişebilirsiniz.{ } küme ayraçları ve uyarı mesajınız görünecektir.

Bileşen sınıfında çağrılabilecek statik yöntemler tanımlamak istemeniz durumunda - statiği kullanmalısınız. Olmasına rağmen:

"Bu blokta tanımlanan yöntemler statiktir, yani bunları herhangi bir bileşen örneği oluşturulmadan önce çalıştırabilirsiniz ve yöntemlerin bileşenlerinizin prop'larına veya durumuna erişimleri yoktur. Statik bir yöntemi, çağıranın statik yönteme bir argüman olarak props'a geçmesini sağlayın. " ( kaynak )

Bazı örnek kodlar:

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

Umarım bu size biraz yardımcı olur, çünkü sorunuzu doğru anlayıp anlamadığımı bilmiyorum, bu yüzden yanlış yorumladıysam düzeltin :)



2

yöntem 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>

Yöntem 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>

yöntem 1, alt bileşen yöntemlerine erişmenin çok kolay ve temiz bir yoludur. Teşekkürler!
gabdara

1

Bileşenleri işlemek ve bir bileşen örneği döndürmek için bu yardımcı yöntemi kullanıyorum. Yöntemler bu örnekte çağrılabilir.

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);
        });
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.