React-Typescript: Denne JSX-tags 'children'-prop forventer et enkelt barn af typen 'Element | undefined', men flere børn blev givet
Jeg bruger react-typescript til min app. Til styling bruger jeg Style component. Jeg har besluttet, at jeg vil oprette mine egne Hooks Input og Password input. Så jeg oprettede først en Input-wrapper, hvor jeg tilføjede de nødvendige inputfelter. Derefter har jeg oprettet et Password input-felt. Jeg udvidede min Password input-komponents props med Input-komponentens props. Men når jeg bruger Input-komponentens wrapper til min password-komponent, får jeg en fejl: Dette JSX-tag's 'children'-prop forventer et enkelt barn af typen 'Element | undefined', men flere børn blev givet.
Jeg ved ikke, hvad jeg gør forkert.
Dette er min Input-wrapper komponent
import React from "react";
import styled from "styled-components";
import ErrorBoundary from "components/errorBoundary";
const Container = styled.div`
position: relative;
`;
const Label = styled.label<{ minimized?: boolean }>`
display: block;
color: ${({ theme }) => theme.inputLabelColor};
font-weight: 400;
font-size: ${({ minimized }) => (minimized ? "11px" : "16px")};
margin-bottom: 5px;
letter-spacing: -0.2px;
position: absolute;
transform: translateY(${({ minimized }) => (minimized ? "9px" : "16px")});
left: 20px;
top: 0;
pointer-events: none;
transition: transform 150ms linear, font-size 150ms linear;
`;
const Error = styled.p`
color: ${({ theme }) => theme.errorTextColor};
`;
const Description = styled.p`
color: blue;
`;
export interface IInputWrapperProps {
label?: string;
required?: boolean;
minimizedLabel?: boolean;
description?: string;
error?: string;
wrapperStyle?: React.CSSProperties;
children?: JSX.Element;
}
export default ({
label,
error,
description,
children,
required,
wrapperStyle,
minimizedLabel
}: IInputWrapperProps) => {
return (
<ErrorBoundary id="InputWrapperErrorBoundary">
<div style={wrapperStyle}>
<Container>
<Label minimized={minimizedLabel}>
{label} {required && <span style={{ color: "red" }}> *</span>}
</Label>
{children}
</Container>
{description && <Description>{description}</Description>}
{error && <Error>{error}</Error>}
</div>
</ErrorBoundary>
);
};
Dette er min adgangskodekomponent
import React, { useState } from "react";
import styled from "styled-components";
import eyeHide from "./eye-svgfiles/eyeHide.svg";
import eyeShow from "./eye-svgfiles/eyeShow.svg";
import InputWrapper, { IInputWrapperProps } from "../wrapper";
const Passwordinput = styled.input`
border: 2px solid ${({ theme }) => theme.inputBorderColorFaded};
background: ${({ theme }) => theme.inputBackgroundColor};
display: block;
border-radius: 5px;
box-shadow: none;
color: ${({ theme }) => theme.inputTextColor};
height: 52px;
width: 100%;
margin: 0;
padding: 1px 15px;
&:focus {
border: 2px solid ${({ theme }) => theme.inputBorderColor};
outline: 0;
}
`;
const Svg = styled.div`
position: absolute;
left: 50%;
top: 65%;
transform: scale(0.8);
`;
export interface IPasswordProps extends IInputWrapperProps {
onChange: (i: string) => void;
value?: string | undefined;
}
export default ({ onChange, value, label, error, ...rest }: IPasswordProps) => {
const [state, setstate] = useState(false);
return (
<div>
<InputWrapper label={label} error={error} {...rest}> //I am getting error in here
<Passwordinput
label={label}
type={state ? "text" : "password"}
onChange={e => onChange(e.target.value)}
value={value}
error={error}
/>
<Svg>
<img
onClick={() => setstate(state => !state)}
style={{ cursor: "pointer" }}
src={state ? eyeShow : eyeHide}
alt="searchIcon"
/>
</Svg>
</InputWrapper>
</div>
);
};
Svar #1
Skriv din grænseflade sådan her:
export interface IInputWrapperProps {
label?: string;
required?: boolean;
minimizedLabel?: boolean;
description?: string;
error?: string;
wrapperStyle?: React.CSSProperties;
children?: JSX.Element|JSX.Element[];
}
faktisk skrivning:
children: JSX.Element|JSX.Element[];
Børnene kan enten være et enkelt JSX-element eller en række af elementer.
Svar #2
Til alle React 18-adoptanter derude
Hvis du lige har opgraderet til React 18 og er ligesom mig, tilføjer du React.PropsWithChildren<> overalt, da typerne for props ikke længere antyder children. Hvis du finder denne tråd, er det sandsynligt, at du stødte på det, jeg stødte på, hvor en tilfældig komponent gav denne fejl tilsyneladende uden grund, selvom det er helt lovligt at have flere elementer som children.
LØSNING:
Mange forskellige ting kan være "react children", inklusive mange primitive typer, og ting som undefined, null og false gengives simpelthen ikke. Min komponent var på en måde sådan her:
<Container>
{maybeNull && <Component notNullThing={maybeNull} />}
{maybeNull2 && <Component notNullThing={maybeNull2} />}
{maybeNull3 && <Component notNullThing={maybeNull3} />}
</Container>
Det viser sig, at maybeNull teknisk set havde typen unknown, og det rokkede ved alt. Jeg rettede det med <>{maybeNull && <Component notNullThing={maybeNull} />}</> (fordi en enkelt unknown af en eller anden grund er lovlig), selvom jeg også kunne have gjort {maybeNull ? <Component notNullThing={maybeNull} /> : null} eller noget lignende.
Jeg tror det er fordi typen React.ReactNode er en stor union, der inkluderer ReactFragment, som er implementeret rekursivt som Iterable<ReactNode>. Det er derfor en ReactNode kan være et array af ReactNodes. Men unknown betyder, at du ikke ved, hvilken af tingene i unionen det er, så du ved ikke, at det kunne være Iterable<ReactNode>. Noget TypeScript-agtigt af den slags.
Svar #3
Det kan fikses med:
interface InputWrapperProps {
...yourProps,
children?: React.ReactNode
}
Håber det hjælper!
Svar #4
For mig fungerer varianten foreslået af shuhat36 fint. Så jeg tilføjede bare fragmentet til børn.
Eksempel med fejl:
<div className="container">
{renderTabs()}
{renderButtons()}
</div>
Og den samme kode, men rettet:
<div className="container">
<>
{renderTabs()}
{renderButtons()}
</>
</div>
