React.js how to properly instantiate child component in parent class

Viewed 74

I am very new to react.js and I have been working on a component class (child) that has functions and a single state object and my end goal is to use this class in a parent class so it, in turn, can call its functions and update the state.

The problem I have been running into is that:

  1. I wasn't aware of a component's lifecycle, and
  2. I come from a heavy C# background

Meaning: I have been treating these component classes like I would any C# class instead of JavaScript. I know that now.

But I need help evaluating my approach and solving this issue I keep seeing:

enter image description here

This is my child Class component

import React, { Component } from 'react'; import axios from 'axios';

export default class ClassB extends Component {
    constructor() {
        super();

        console.log("ClassB constructor got called");

        this.state = {
            users: [{ name: '', email: '' }]
        };
    }

    getUsers() {
        let URL = "https://localhost:5001/api/FooController/FooAction"
        let myParam = 100;

        axios.get(URL,
            {
                params: { myParam }
            })
            .then(response => {
                // handle logic here...

            }).catch(function (error) {
                console.log('What happened? ' + error.response.data);
            });
    }

    addUserData(name, email) {
        this.setState(this.state, { users: [name, email] });
    }

    componentDidMount() {
        console.log("ClassB componentDidMount got called");     
    }

    render() {
        console.log("ClassB render got called");
        return ( null )
    }
}

And in my parent class (Home.js) I am instantiating the child class (ClassB.js) and using its instance as such:

import React, { Component } from 'react';
import ClassB from './ClassB'
import ClassC from './ClassC'

const classBComponent = new ClassB();

export class Home extends Component {
    static displayName = Home.name;
    

    constructor() {
        super();

    }

    componentDidMount() {
        this.timerID = setInterval(() => {
            classBComponent.getUserValues();
        }, 3000);
    }

    componentWillUnmount() {
        clearInterval(this.timerID);
    }

    render() {

        myComponent.render();

        return (
            <div className="container">
                <h1>My Other Component:</h1>
                <div className="row">
                    <div className="col-sm">
                        <ClassC name={[{ component: classBComponent, info: ['John', 'john123@123.com'] }]} />
                    </div>
                </div>
            </div>
        );
    }
}

In this parent class I intend to call the "getUserValues() methods from the ClassB component. I also have another child component (ClassC), which is a functional component, and I want to pass the instantiated ClassB component so it can access its functions and states as well. But, in ClassC component, when I call "addUserData()" method it gives me the error I pasted above (see image).

Here is how I have my ClassC set up:

import React, { useEffect } from 'react';
import axios from 'axios';

const ClassC = (props) => {

    // variables
    let user  = props.name[0].info[0];
    let email = props.name[0].info[1];

    // component
    const component = props.name[0].component;


    // renders component
    function componentMount() {
        component.addSimModelNodeInfo(user, email);
    }

    // leaves the component
    function componentUnmount() {       

    }

    useEffect(() => {
        componentMount();
        return () => {
            componentUnmount();
        }
    }, [])

    return (
        <div className="card shadow-sm p-3 mb-5 bg-white rounded">
            <div className="card-header">
                <h5>{name}</h5>
                <h5>{email}</h5>
            </div>          
        </div>
    );
}

export default ClassC;

I mentioned earlier how I didn't have a solid grasp on components' lifecycles. I placed those console.logs in ClassB only to realize that the only method getting called is the constructor. The componentDidMount() function never gets called and neither does the render(). Why is that? I know its linked to that error which is why my ClassB component never gets "mounted". What am I doing wrong? Many thanks in advance.

1 Answers

Here's an example of calling a parent component function from a child component. I'm using functional components for brevity, but this is totally possible with class-based as well.

If you're not familiar with functional components, you can consider props to be like this.props, and the function itself is similar to the render() method in classful components. There's more to it, but for this small example that should help you if you need to translate.

const ChildComponent = (props) => <button onClick={props.onClick} />

const ParentComponent = () => {
  const onClick = () => {
    console.log("Click Clack");
  }
  return <ChildComponent onClick={onClick} />;
};
Related