hur kan jag få barnets state-värde till föräldern med useRef i reactjs + typescript (hooks)
Jag är ny på Typescript. Jag behöver få barnets state-värden till föräldern med hjälp av ref på en knapptryckning för att uppdatera reducer-värdena.
Jag har försökt att skicka ett ref till barnet men jag får fel som liknar detta:
Typen '{ value: string; onChange: Dispatch<SetStateAction>; ref: MutableRefObject<HTMLInputElement | undefined>; }' kan inte tilldelas typen 'IntrinsicAttributes & Props & { children?: ReactNode; }'.
Egenskapen 'ref' finns inte på typen 'IntrinsicAttributes & Props & { children?: ReactNode; }'.ts(2322)
föräldrakomponent
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);
barnkomponent
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;
Svar #1
Du får det felet eftersom Welcome inte är designad för att ta emot en ref-prop.
ref är ett reserverat prop-namn i React, så för att skicka ett prop ref till en barnkomponent måste den barnkomponenten använda React.forwardRef för att ta emot ref-propet.
Du kan skicka ref-objektet direkt med vilket annat prop-namn som helst, till exempel myRef. I det fallet behöver du inte använda forwardRef men du måste se till att barnets props accepterar en prop myRef som är en ref.
Typen för själva ref beror på var den så småningom kommer att fästas i DOM. Antagligen en 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}/>
...
Detta låter dig interagera med DOM. Men det verkar inte vara vad du egentligen vill göra.
Jag behöver få barnets state-värden till föräldern med ref vid ett knappklick för att uppdatera reducer-värdena.
Skicka bara en callback! Bör tillståndet ens lagras i barnet, eller kan du lyfta upp det till föräldern?
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
}} />
...
Svar #2
Ett mycket enklare sätt är att använda useRef-hooken som är inbyggd i React med den reserverade ref-egenskapen. Den fungerar bara på muterbara objekt, så du behöver inte oroa dig för att skriva typen själv.
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);
