I want to call a method exposed by a React component from the instance of a React Element.
For example, in this jsfiddle. I want to call the alertMessage
method from the HelloElement
reference.
Is there a way to achieve this without having to write additional wrappers?
Edit (copied code from 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')
);
This question is related to
reactjs
With the render
method potentially deprecating the returned value, the recommended approach is now to attach a callback ref to the root element. Like this:
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.
Here's a full example:
var onButtonClick = function() {_x000D_
window.helloComponent.alertMessage();_x000D_
}_x000D_
_x000D_
class Hello extends React.Component {_x000D_
alertMessage() {_x000D_
alert(this.props.name);_x000D_
}_x000D_
_x000D_
render() {_x000D_
return React.createElement("div", null, "Hello ", this.props.name);_x000D_
}_x000D_
};_x000D_
_x000D_
ReactDOM.render( <Hello name="World" ref={(element) => {window.helloComponent = element}}/>, document.getElementById('container'));
_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>_x000D_
<div id="container"></div>_x000D_
<button onclick="onButtonClick()">Click me!</button>
_x000D_
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});
}
}
And then somewhere else:
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');
}
}
I haven't tested this exact code, but this is along the lines of what I did in a project of mine and it works nicely :). Of course this is a bad example, you should just use props for this, but in my case the sub-component did an API call which I wanted to keep inside that component. In such a case this is a nice solution.
If you are in ES6 just use the "static" keyword on your method from your example would be the following: static alertMessage: function() {
...
},
Hope can help anyone out there :)
method 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>
Method 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>
You can do like
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;
Now from outside of this component you can called like this below
window.helloComponent.alertMessage();
You can just add an onClick
handler to the div with the function (onClick
is React's own implementation of onClick
) and you can access the property within { }
curly braces, and your alert message will appear.
In case you wish to define static methods that can be called on the component class - you should use statics. Although:
"Methods defined within this block are static, meaning that you can run them before any component instances are created, and the methods do not have access to the props or state of your components. If you want to check the value of props in a static method, have the caller pass in the props as an argument to the static method." (source)
Some example code:
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:)
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>
</>
)
}
Good Luck...
With React17 you can use useImperativeHandle hook.
useImperativeHandle customizes the instance value that is exposed to parent components when using ref. As always, imperative code using refs should be avoided in most cases. useImperativeHandle should be used with forwardRef:
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
In this example, a parent component that renders would be able to call inputRef.current.focus().
class AppProvider extends Component {
constructor() {
super();
window.alertMessage = this.alertMessage.bind(this);
}
alertMessage() {
console.log('Hello World');
}
}
You can call this method from the window by using window.alertMessage()
.
I use this helper method to render components and return an component instance. Methods can be called on that 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);
});
}
It appears statics are deprecated, and the other methods of exposing some functions with render
seem convoluted. Meanwhile, this Stack Overflow answer about debugging React, while seeming hack-y, did the job for me.
Source: Stackoverflow.com