0
votes

I am new to Typescript. I need to get the child state values to the parent using ref on a button click to update the reducer values.

I have tried passing a ref to the child but I am getting errors similar to this:

Type '{ value: string; onChange: Dispatch<SetStateAction>; ref: MutableRefObject<HTMLInputElement | undefined>; }' is not assignable to type 'IntrinsicAttributes & Props & { children?: ReactNode; }'.

Property 'ref' does not exist on type 'IntrinsicAttributes & Props & { children?: ReactNode; }'.ts(2322)

parent component

import React, from "react";
import styled from "styled-components";
import {
    Page,
    Welcome,
    ErrorBoundary
} from "components";
const ParentDiv = styled.div`
            margin: 0 410px 30px 15px;
            `;

export const CreateEvent = (props: any) => {

    return (
        <Page title='Dashboard'>
            <ErrorBoundary>
                {(() => {
                    switch (activeEventStage?.step) {
                        case 1:
                            return (
                                <ErrorBoundary>
                                    <Welcome />
                                </ErrorBoundary>
                            );
                        default:
                            return null;
                    }
                })()}
            </ErrorBoundary>
        </Page>
    );
};
export default withRouter(CreateEvent);

child component

import React, { useState } from "react";
import { Row, Col } from "react-bootstrap";

export const Welcome = () => {
    const { t } = useTranslation();
    const [state, setState] = useState({
        welBannerTagline: "",
        welHeroTitle: "",
    });

    return (
        <CreateEventFormContainer
            title={t("event.create.title")}
            subTitile={t("welcome.subTitle")}
        >
            <>
                <Row>
                    <Col lg='6'>
                        <DropZoneInputField
                            titleName={t("welcome.bgImage.title")}
                            onSelectedFiles={onDropFiles}
                            imageType='bgImage'
                            value={state.welBgFilename}
                        />
                    </Col>
                    <Col lg='6'>
                        <DropZoneInputField
                            titleName={t("welcome.banner.title")}
                            onSelectedFiles={onDropFiles}
                            imageType='bannerImage'
                            value={state.welBannerFilname}
                        />
                    </Col>
                </Row>
            </>
        </CreateEventFormContainer>
    );
};
export default Welcome;
1
where are u using useRef? I dont see it in the code aboveNhut Dinh Ba
i have removed that because its breaking my work, i only need the solution using typescript in hooks to get the child state valuesKishan Jaiswal

1 Answers

0
votes

You get that error because Welcome is not designed to accept a ref prop.

ref is a reserved prop name in React so in order to pass a prop ref to a child component, that child must use React.forwardRef to accept the ref prop.

You can pass the ref object directly with any other prop name, for example myRef. In that case you don't need to use forwardRef but you do need to make sure that the props of the child accept a prop myRef which is a ref.

The type for the ref itself depends on where it will be eventually attached to the DOM. Probably an HTMLButtonElement?

interface WelcomeProps {
    myRef: React.MutableRefObject<HTMLButtonElement | null>;
}

export const Welcome = ({myRef}: WelcomeProps) => {
...
export const CreateEvent = (props: RouteComponentProps) => {
    const refObject = React.useRef<HTMLButtonElement | null>(null);
    return (
...
       <Welcome myRef={refObject}/>
...

This allows you to interact with the DOM. But that doesn't seem like what you actually want to do.

I need to get the child state values to the parent using ref on a button click to update the reducer values.

Just pass a callback! Should the state even be stored in the child, or can you lift it up to the parent?

interface CallbackValue {
    // what properties does the callback want to receive?
    welBannerTagline: string;
    welHeroTitle: string;
}

interface WelcomeProps {
    myCallback: (value: CallbackValue) => void;
}

export const Welcome = ({myCallback}: WelcomeProps) => {
    const [state, setState] = useState({
        welBannerTagline: "",
        welHeroTitle: "",
    });

    const handleEvent = () => {
        myCallback(state);
    }
...
export const CreateEvent = (props: RouteComponentProps) => {
    return (
...
       <Welcome myCallback={(value) => {
           // do something here with the value
       }} />
...