从外部调用React组件方法


95

我想从React元素的实例中调用React组件公开的方法。

例如,在此jsfiddle中。我想alertMessageHelloElement参考中调用该方法。

有没有一种方法可以实现而无需编写其他包装程序?

编辑(从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的好方法。如果您确实需要重用某些东西,请在第三个文件中创建一个单独的通用帮助程序,并将其用于您的按钮以及react组件。
茶味

Answers:


56

有两种访问内部函数的方法。一个实例级别,如您所愿,另一个静态级别。

实例

您需要在从返回时调用函数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

44

你可以喜欢

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
其实简单又实用!就像应该的那样。它的简单性让我印象深刻。真的没想到。如果您应该拥有越来越多的组件,那么这种方法可能行不通。谢谢!
莱昂纳多·马菲

6
添加全局变量不是一个好的解决方案。有关全局变量为何无效的
SalvatoreZappalà18/

3
感谢投反对票!!是的,全局变量不好,但这是解决问题的一种方法。
库沙尔·in那

这正是我需要的务实而简单的解决方案,谢谢!
Florent Destremau

2
它可以工作,但是如果您在同一页面上有多个相同的组件,它将无法工作。
gaurav

26

我做了这样的事情:

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

}

我还没有测试这个确切的代码,但这与我在我的项目中所做的工作很相似,并且效果很好:)。当然,这是一个不好的例子,您应该为此使用props,但是在我的情况下,子组件执行了API调用,我想保留在该组件内。在这种情况下,这是一个不错的解决方案。


5
我想你的意思是this.cowCallbacks.say('moo')
史蒂文(Steven)

顺便说一句,可以传递this给回调(它将是Cow的一个实例)而不是callbacks
WebBrother

@WebBrother是的,但是那会更加hacky
gitaarik

6

由于该render方法可能不建议使用返回值,因此建议的方法现在是将回调引用附加到根元素。像这样:

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()?,它不会将组件绑定到窗口
Guerrilla

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

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

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

您可以使用从窗口调用此方法window.alertMessage()


这会起作用,但是出于许多原因,添加全局变量并不是一个好的解决方案。您可以在此处找到有关为什么全局变量不好的更多信息:wiki.c2.com/?GlobalVariablesAreBad
SalvatoreZappalà18

3

如果您使用的是ES6,则只需在示例中使用“ static”关键字即可,示例如下: static alertMessage: function() { ...
},

希望可以帮助任何人:)


您无法在静态函数中访问道具或状态。
SerdarDeğirmenci17年

好的,但是问题是要访问alertMessage()函数,因此您可以使用HelloElement.alertMessage()。
darmis '17

通常,在不使用props和state的情况下调用函数无效。但是,由于您对实现职能的权利是对的,所以我将取消表决
SerdarDeğirmenci17年

2

您可以onClick使用函数(onClick是React自己的实现onClick)向div添加一个处理程序,并且可以在{ }花括号中访问该属性,然后会出现警告消息。

如果您希望定义可以在组件类上调用的静态方法,则应使用静态方法。虽然:

“此块中定义的方法是静态的,这意味着您可以在创建任何组件实例之前运行它们,并且这些方法无权访问props或组件的状态。如果要检查static中props的值,方法,让调用者将props作为静态方法的参数传入。” (来源

一些示例代码:

    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是访问子组件方法的非常简单和干净的方法。谢谢!
gabdara19年

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);
        });
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.