Reactコンポーネントメソッドを外部から呼び出す


92

React要素のインスタンスからReactコンポーネントによって公開されたメソッドを呼び出したいのですが。

例えば、これでjsfiddle。リファレンスalertMessageからメソッドを呼び出したいHelloElement

追加のラッパーを記述せずにこれを実現する方法はありますか?

編集(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
理想的ではありませんが、JSFiddleは十分に一般的であるため、反対票は必要ありません。
ジェフフェアリー2015

私はあなたがそのようなことを正当化するあなたのユースケースが何であることができるのだろうと思っています。これは、アプリケーションのimoを設計するための良い方法ではありません。何かを再利用する必要がある場合は、3番目のファイルに別の共通ヘルパーを作成し、それをボタンと反応コンポーネントに使用してください。
1

回答:


55

内部関数にアクセスするには2つの方法があります。1つはインスタンスレベルで、必要に応じて、もう1つは静的レベルです。

インスタンス

からの戻り時に関数を呼び出す必要がありますReact.render。下記参照。

静的

ReactJS Staticsを見てください。ただし、静的関数はしないアクセスインスタンス・レベルのデータは、そうすることができることthisであろう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'));

その後、行いますHelloRendered.alertMessage()


13
renderの戻り値の使用は非推奨と見なされており、パフォーマンスの向上を可能にするために将来のバージョンで削除される予定です。コンポーネントインスタンスオブジェクトへの参照を取得するためのサポートされている方法はref、インスタンスをパラメーターとして呼び出される関数であるプロパティを追加することです。これにより、最上位にないオブジェクトにアクセスすることもできます。たとえば、レンダリングしている<MuiThemeProvider><Hello ref={setHelloRef} /></MuiThemeProvider>場合、正しい参照がsetHelloRef関数に渡されるのではなく、関数に渡されますMuiThemeProvider
Periata Breatta 16

43

あなたは好きにできます

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;

このコンポーネントの外側から、以下のように呼び出すことができます

window.helloComponent.alertMessage();

1
実際、シンプルで機能的です!それがあるはずのように。私はそれがいかに単純であるかに非常に感銘を受けました。本当に考えなかった。おそらく、必要なコンポーネントが増えれば、このアプローチはそれほどうまくいきません。ありがとうございました!
Leonardo Maffei

6
グローバル変数を追加することは良い解決策ではありません。グローバル変数が悪い理由の詳細:wiki.c2.com/?GlobalVariablesAreBad
SalvatoreZappalà2018年

3
反対票をありがとう!はい、グローバル変数は良くありませんが、それはあなたの問題を解決する方法です。
Kushal Jain

これはまさに私が必要とした実用的でシンプルなソリューションです、ありがとう!
Florent Destremau

2
動作しましたが、同じページに同じコンポーネントが複数ある場合は動作しません。
gaurav

24

私はこのようなことをしました:

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

}

そして、他のどこか:

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

}

私はこの正確なコードをテストしていませんが、これは私が私のプロジェクトでやったことに沿ったもので、うまく機能します:)。もちろん、これは悪い例です。これにはプロップを使用する必要がありますが、私の場合、サブコンポーネントがAPI呼び出しを実行し、そのコンポーネント内に保持したいと考えていました。そのような場合、これは素晴らしい解決策です。


5
私はあなたが意味したと思うthis.cowCallbacks.say('moo')
スティーブン

ところで、のthis代わりにコールバック(Cowのインスタンスになります)に渡すことができますcallbacks
WebBrother

@WebBrotherはい、しかしそれはもっとハッキーです
gitaarik

6

ではrenderこの方法は、潜在的に返される値を卑下、推奨されるアプローチは、ルート要素にコールバックREFを添付することになりました。このような:

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

これはwindow.helloComponentを使用してアクセスでき、そのメソッドにはwindow.helloComponent.METHODを使用してアクセスできます。

ここに完全な例があります:

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>


参照をウィンドウオブジェクトではなくローカル状態に置く方が良い... ref={component => {this.setState({ helloComponent: component; })}} 次に、クリックハンドラーで... this.state.helloComponent.alertMessage();
Bill Dagg

私の以前のコメントに加えて...または、もっと良いことに、コンポーネントのalertMessageメソッドを状態に置くだけです。
Bill Dagg

これを試してみると、Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?コンポーネントがウィンドウにバインドされません
ゲリラ

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

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

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

このメソッドは、を使用してウィンドウから呼び出すことができますwindow.alertMessage()


これは機能しますが、グローバル変数を追加することは、多くの理由で適切な解決策ではありません。グローバル変数が悪い理由の詳細については、wiki.c2.com
SalvatoreZappalàNov

3

ES6を使用している場合、メソッドの "static"キーワードを使用するだけで、次の例のようになります。 static alertMessage: function() { ...
},

そこにいる誰かを助けてくれることを願っています:)


静的関数で小道具や状態に到達することはできません。
SerdarDeğirmenci2017年

はい、でも、HelloElement.alertMessage()を使用できるように、alertMessage()関数にアクセスしようとしていました。
Darmis '10 / 10/06

通常、propsとstateを使用せずに関数を呼び出しても効果はありません。しかし、あなたが機能に到達することについて正しいので、私は私の投票を削除します
SerdarDeğirmenci17年

2

onClick関数を使用してハンドラーをdivに追加するだけで(onClickReactのの独自の実装ですonClick)、{ }中括弧内のプロパティにアクセスでき、アラートメッセージが表示されます。

コンポーネントクラスで呼び出すことができる静的メソッドを定義する場合は、静的メソッドを使用する必要があります。ただし:

「このブロック内で定義されたメソッドは静的です。つまり、コンポーネントインスタンスが作成される前にそれらを実行でき、メソッドはコンポーネントのプロップまたは状態にアクセスできません。静的なプロップの値をチェックする場合メソッドでは、呼び出し元に静的メソッドへの引数として小道具を渡します。」(ソース

いくつかのサンプルコード:

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

私があなたの質問を正しく理解したかどうかわからないので、これがあなたに少し役立つことを願っています。間違って解釈した場合は訂正してください:)



2

方法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>

方法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>

メソッド1は、子コンポーネントのメソッドにアクセスするための非常に簡単でクリーンな方法です。ありがとう!
gabdara

2

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

幸運を...


1

このヘルパーメソッドを使用してコンポーネントをレンダリングし、コンポーネントインスタンスを返します。そのインスタンスでメソッドを呼び出すことができます。

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);
        });
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.