Call a React component method from outside

我想从 React Element 的实例中调用一个由 React 组件公开的方法。

例如,在这个 Jsfiddle中,我想从 HelloElement引用调用 alertMessage方法。

有没有一种方法可以实现这一点,而不必编写额外的包装器?

编辑 (从 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')
);
164166 次浏览

访问内部函数有两种方法: 一种是实例级,另一种是静态级。

Instance

您需要在从 React.render返回时调用该函数。

静电干扰

然而,请注意,静态函数不能访问实例级数据,因此 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()

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

如果您希望定义可以在组件类上调用的静态方法,那么您应该使用 static。不过:

”此块中定义的方法是静态的,这意味着您可以在创建任何组件实例之前运行它们,而且这些方法不能访问您组件的道具或状态。如果你想在静态方法中检查道具的值,让调用者将道具作为参数传递给静态方法。”(来源)

一些示例代码:

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

Hope this helps you a bit, because i don't know if I understood your question correctly, so correct me if i interpreted it wrong:)

似乎静态是不被推荐的,而用 render公开某些函数的其他方法似乎令人费解。与此同时,有关调试的堆栈溢出答案,虽然看起来像黑客一样,为我完成了这项工作。

I've done something like this:

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 调用,我希望将其保留在该组件中。在这种情况下,这是一个很好的解决方案。

如果您在 ES6中,只需在您的方法上使用“ static”关键字,从示例中可以看到以下内容: < code > static alertMessage: function (){ ...
} ,

希望可以帮助任何人:)

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

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

which we can then access using window.helloComponent, and any of its methods can be accessed with 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>

你可以这么做

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();
class AppProvider extends Component {
constructor() {
super();


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


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

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

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

I use this helper method to render components and return an component instance. 方法可以在该实例上调用。

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

1. 使用 React hooks - useImperativeHandle + useRef

const MyComponent = ({myRef}) => {
const handleClick = () => alert('hello world')
useImperativeHandle(myRef, () => ({
handleClick
}), [/* dependencies (if any) */])
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>
</>
)
}

2. With only 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>
</>
)
}

祝你好运..。

对于 React17,您可以使用 useImperativeHandle 钩子。

UseImperativeHandle 自定义在使用 ref 时公开给父组件的实例值。像往常一样,在大多数情况下应该避免使用引用的命令式代码。UseImperativeHandle 应该与 forwardRef 一起使用:

function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));


return <input ref={inputRef} ... />;
}


FancyInput = forwardRef(FancyInput);

在本例中,呈现的父组件将能够调用 inputRef.current.focus ()。

对于动态组件,我使用了带有道具的 来自道具方法。

您可以创建函数来更新子组件的道具,子组件中的 来自道具将为您处理道具的更新。 For example:

class Parent extends React.Component
{
constructor(props)
{
super(props);


this.state = {  selectMachine: '1' };


this.setComponent = null;
       

}


handleMachineChange = (e) =>{
this.setState({selectMachine: e.target.value})
}


}


class Child extends React.Component
{
state = {
programForm: {
machine_id: '1',
}
}


constructor(props)
{
super(props);
}




static getDerivedStateFromProps(props, state) {
if(props.selectMachine !== state.programForm.machine_id){
//Change in props
return{
programForm:  { ...state.programForm, machine_id: props.selectMachine }
};
}
return null; // No change to state
}
}

尽管这个问题已经结束,我还是想分享另一种方法。

以下是对我有效的方法:

子组件

  1. 子组件接受一个道具,我们称之为 关于输出方法,目的是返回这个组件想要提供给消费者的实例方法集。

  2. 需要公开哪些内容的决定是在构造函数级别完成的。

Consumer Component

  1. 通过支持 关于输出方法的方法 & 在处理程序中保持方法集的副本。

  2. 只要需要,父组件就可以调用公开的方法

检查样品 给你