Reputation: 664
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;
Upvotes: 2
Views: 1695
Reputation: 156
A much simpler way is to use the useRef
hook built into React with the reserved ref
prop. It only works on mutable objects so you don't have to worry about typing it yourself.
import { useRef } from "react";
export const CreateEvent = (props: any) => {
const welcomeRef = useRef();
return (
<Page title='Dashboard'>
<ErrorBoundary>
{(() => {
switch (activeEventStage?.step) {
case 1:
return (
<ErrorBoundary>
<Welcome ref={welcomeRef} />
</ErrorBoundary>
);
default:
return null;
}
})()}
</ErrorBoundary>
</Page>
);
};
export default withRouter(CreateEvent);
Upvotes: 1
Reputation: 42188
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
}} />
...
Upvotes: 1