Search code examples
reactjstypescripttsx

Get class instance of ReactElement


I am trying to get the instance of a ReactElement Component.

I have the following (example) code:

import { Component, ReactElement } from "react";
import ReactDOM from "react-dom";

class Foo extends Component {
    public myAwesomeString = "meow";

    public myAwesomeFunction(echo: string) {
        console.log(echo);
    }

    public render() {
        return <span>Some content</span>;
    }
}

class Bar extends Component<{ children: ReactElement }> {
    public componentDidMount() {
        // this.props.children.myAwesomeFunction("meow") <-- How would I do this?
    }

    public render() {
        return (
            <>
                {this.props.children}
                <span>{/* this.props.children.myAwesomeString */}</span> {/* <-- And this?*/}
            </>
        );
    }
}

ReactDOM.render(
    <Bar>
        <Foo />
    </Bar>,
    document.getElementById("root")
);

Is there any way to get the instance Foo from Bar when Foo is a child of Bar?
I have tried using this.props.children.ref but I just got null...
Any ideas?


Solution

  • You can use Context's to register the child component:

    import { Component, ReactElement, createContext, ContextType } from "react";
    import ReactDOM from "react-dom";
    
    const RegisterContext = createContext({ register: (cp: Foo) => {} });
    
    class Foo extends Component {
        public static contextType = RegisterContext;
        declare context: ContextType<typeof RegisterContext>;
    
        public componentDidMount() {
            this.context.register(this); // <--
        }
    
        public myAwesomeString = "meow";
    
        public myAwesomeFunction(echo: string) {
            console.log(echo);
        }
    
        public render() {
            return <span>Some content</span>;
        }
    }
    
    class Bar extends Component<{ children: ReactElement }> {
        private foo!: Foo;
    
        public componentDidMount() {
            this.foo.myAwesomeFunction("meow");
        }
    
        public registerFoo(foo: Foo) {
            this.foo = foo;
        }
    
        public render() {
            return (
                <>
                    <RegisterContext.Provider
                        value={{ register: this.registerFoo }}>
                        {this.props.children}
                    </RegisterContext.Provider>
                    <span>{this.foo.myAwesomeString}</span>
                </>
            );
        }
    }
    
    ReactDOM.render(
        <Bar>
            <Foo />
        </Bar>,
        document.getElementById("root")
    );
    
    

    I haven't tested this specific example out yet, but it looks as if it would work.