How to call inherited function in react child component - reactjs

I have 2 components. One extendind another like this
export default class Parent extends React.Component {
myCustomFunction = () => {
..
this.setState({
myVar: 'pippo'
});
}
}
export default class Child extends Parent {
myCustomFunction = () => {
//I want to call here my parent myCustomFunction
..
this.setState({
myVar: 'pluto',
otherVar: 'paperino'
});
}
render (){
return
<button onClick={this.myCustomFunction } />
}
}
When someone click on button in Child I want to run the Parent function and then do some other stuff on the state.
How can I achieve this without coping the Parent in the Child?

There's lots of approaches but I think you're looking for how to inherit the Parent's function like you would traditionally in any class inheritance model.
class Parent extends React.Component {
constructor() {
super();
}
parentFunc() {
console.log(`Parent`);
}
}
class Child extends Parent {
constructor() {
super();
}
childFunc() {
console.log(`Child`);
super.parentFunc();
}
render() {
return <button onClick={this.childFunc}>Click me</button>;
}
}
CodeSandbox here https://codesandbox.io/s/k3n1664323
MDN docs on super() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
p.s. You cannot call super in the context of an arrow function, you will need to use a regular function expression or take a different approach, potentially like the other answer suggested. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Related

React life cycle methods won't fire, when calling React.Component<props,state>'s render() method

I've got a parent react component, which dynamically generates an array of custom child elements. The parent's lifecycle methods are getting fired properly. It's child elements life cycle methods won't get called. My question is: why?
Parent:
export default class Parent extends React.Component<IParentProps, IParentState> {
public children: Array<IChild & React.Component> = new ArrayArray<IChild & React.Component>();
constructor(props) {
super(props);
this.children.push(new Child({
options: {}
}));
this.children.push(new Child({
options: {}
}));
console.log('constructor(props)');
}
public componentWillMount() {
// gets called
}
public render(): React.ReactElement<IParentProps> {
return (
<div>
{this.children[this.state.currentStep].render()}
</div>
);
}
}
Child:
export default class Child extends React.Component<IChildProps, IChildState> implements IChild {
//#region IStep implementation
//#endregion
constructor(props) {
super(props);
}
public componentWillMount() {
// won't get called, neither any other life cycle method, such as componentDidMount etc.
}
public render(): React.ReactElement<IChildProps> {
// gets called
return (
<div>
I am child
</div>
);
}
}
Any idea?
You can't call render method of a child like this (/!\ bad practice).
React is unable to know that this component exist.
Here is a fix:
export default class Parent extends React.Component<IParentProps, IParentState> {
public children: Array<IChild & React.Component> = new ArrayArray<IChild & React.Component>();
constructor(props) {
super(props);
this.children.push(new Child({
options: {}
}));
this.children.push(new Child({
options: {}
}));
console.log('constructor(props)');
}
public componentWillMount() {
// gets called
}
public render(): React.ReactElement<IParentProps> {
const Child = this.children[this.state.currentStep]
return (
<div>
<Child />
</div>
);
}
}
You are not meant to ever call render directly.
You need to instead use Reacts mounting and management via React.createElement
An example of how to achieve this:
render(): React.ReactElement<IParentProps> {
return (
<div>
{React.createElement(this.children[this.state.currentStep], props, children)}
</div>
);
}

Reactjs: Parent function call triggered by a child

So I am building my first react project and stumbled upon following problem:
In my App.js (main application) I got a function and render my components:
class App extends Component {
constructor(props) {
super(props);
this.candidateCounter = 0;
this.setCandidateVote = this.setCandidateVote.bind(this);
}
...
setCounter (name) {
this.candidateCounter++;
console.log(this.candidateCounter);
}
render() {
...
<Candidates setCounter={this.setCounter} />
}
}
The child component Candidates.jsx has another function and thus calls another component:
export class Candidates extends React.Component {
constructor(props) {
super(props);
this.AppProps = props;
}
...
registerVote(name) {
...
this.AppProps.setCounter(name);
}
render() {
...
<MyButton id={this.state.candidates[i].name} register={this.registerVote} />
}
And the last component MyButton.jsx looks like this:
export class MyButton extends React.Component {
constructor(props) {
super();
this.ParentProps = props;
this.state = { active: false }
}
buttonActiveHandler = () => {
this.setState({
active: !this.state.active
});
if (this.state.active === false) {
this.ParentProps.register(this.ParentProps.id);
}
else {
...
}
}
render() {
return (
<Button content='Click here' toggle active={this.state.active} onClick={this.buttonActiveHandler} />
);
}
}
I have successfully debugged that all functions calls are working except when the grandchild MyButton has triggered the registerVote() function in my Candidates module. Logging in this method gets printed but it cannot call this.AppProps.setCounter() from the parent App. I receive the following error:
TypeError: Cannot read property 'setCounter' of undefined
I hope this wasn't too complicated explained, any help is appreciated :)
Simply bind the function in the constructor of the class as #qasimalbaqali stated in his comment.
constructor(props) {
super();
this.registerVote = this.registerVote.bind(this);
}

typescript calling connected child ref instance method

to be simple, I have a child component connected by redux
class Child extends React.Component {
foo () {}
}
export default connect()(Child);
and a parent contains it
class Parent extends React.Component {
childRef: React.RefObject<Child> = React.createRef()
bar () {
if (this.childRef.current) {
/*
* here typescript complains that
* Property 'foo' does not exist on
* type 'ConnectedComponentClass<typeof Child...'
*/
this.childRef.current.foo();
}
}
render () {
return (
<Child ref={this.childRef} />
);
}
}
I've tried to set the generic type
<React.ComponentType<Child>>
explicitly when exporting child component, but still not working.
I had the same issue and couldn't find a legitimate solution. I did, however, manage to hack it by redeclaring the child component with type 'any', like so:
class Parent extends React.Component {
childRef: React.RefObject<Child> = React.createRef()
bar () {
if (this.childRef.current) {
const childRef: any = this.childRef.current;
childRef.foo();
}
}
render () {
return (
<Child ref={this.childRef} />
);
}
}
If you ever managed to come up with a better solution i'd like to hear it.

Is it possible to get ref of props.children?

I want to get ref of Child component. What is the best way to do this?
class Child extends React.Component {
render() {
return <div>Child</div>;
}
}
class GetRef extends React.Component {
componentDidMount() {
console.log(this.props.children.ref)
}
render() {
return this.props.children
}
}
Edit:
So I can use it like this
<GetRef><Child/></GetRef>
I assumed that GetRef children has only one child, then you can retrieve the ref of the only child component with this code
class Child extends React.Component {
render() {
return <div>Child</div>;
}
}
class GetRef extends React.Component {
componentDidMount() {
console.log(this.ref);
}
render() {
const childElement = React.Children.only(this.props.children);
return React.cloneElement(
childElement,
{ ref: el => this.ref = el }
);
}
}
class App extends Component {
render() {
return <GetRef><Child/></GetRef>;
}
}
Here is the complete example on stackblitz
If this.props.children has more than one child, you will need to iterate over the children and store all the refs into an array
This is where forwardRef can be used:
class GetRef extends React.Component {
render() {
console.log(this.props.forwardRef)
}
}
const ref = React.createRef();
<Child forwardRef={ref} />
Alternatively, you may also use:
<Child ref="childRef" .../>
// In the parent component
React.findDOMNode(this.refs.childRef)
But take a look at Exposing DOM Refs to Parent Components to know whether to use ref or not:
In rare cases, you might want to have access to a child’s DOM node from a parent component. This is generally not recommended because it breaks component encapsulation, but it can occasionally be useful for triggering focus or measuring the size or position of a child DOM node.

ReactJS - How to use method from other component of other file? [duplicate]

I have two components. I want to call a method of the first component from the second component. How can I do it?
Here is my code.
First Component
class Header extends React.Component{
constructor(){
super();
}
checkClick(e, notyId){
alert(notyId);
}
}
export default Header;
Second Component
class PopupOver extends React.Component{
constructor(){
super();
// here i need to call Header class function check click....
// How to call Header.checkClick() from this class
}
render(){
return (
<div className="displayinline col-md-12 ">
Hello
</div>
);
}
}
export default PopupOver;
You can do something like this
import React from 'react';
class Header extends React.Component {
constructor() {
super();
}
checkClick(e, notyId) {
alert(notyId);
}
render() {
return (
<PopupOver func ={this.checkClick } />
)
}
};
class PopupOver extends React.Component {
constructor(props) {
super(props);
this.props.func(this, 1234);
}
render() {
return (
<div className="displayinline col-md-12 ">
Hello
</div>
);
}
}
export default Header;
Using statics
var MyComponent = React.createClass({
statics: {
customMethod: function(foo) {
return foo === 'bar';
}
},
render: function() {
}
});
MyComponent.customMethod('bar'); // true
Well, actually, React is not suitable for calling child methods from the parent. Some frameworks, like Cycle.js, allow easily access data both from parent and child, and react to it.
Also, there is a good chance you don't really need it. Consider calling it into existing component, it is much more independent solution. But sometimes you still need it, and then you have few choices:
Pass method down, if it is a child (the easiest one, and it is one of the passed properties)
add events library; in React ecosystem Flux approach is the most known, with Redux library. You separate all events into separated state and actions, and dispatch them from components
if you need to use function from the child in a parent component, you can wrap in a third component, and clone parent with augmented props.
UPD: if you need to share some functionality which doesn't involve any state (like static functions in OOP), then there is no need to contain it inside components. Just declare it separately and invoke when need:
let counter = 0;
function handleInstantiate() {
counter++;
}
constructor(props) {
super(props);
handleInstantiate();
}
You could do this to call a method of the child component from the parent component.
import React from 'react';
class Header extends React.Component {
constructor() {
super();
this.childComponentRef;
}
getChildComponent = (childComponent) => {
this.childComponentRef = childComponent;
this.childComponentRef.sayHi();
}
render() {
return (
<ChildComponent getChildComponent={this.getChildComponent} />
)
}
};
class ChildComponent extends React.Component {
componentDidMount () {
this.props.getChildComponent(this);
}
sayHi = () => {
alert("hi");
}
render() {
return (
<div className="displayinline col-md-12 ">
Hello
</div>
);
}
}
export default Header;

Resources