Im trying to reused the about component to contact component. but i can't pass the data using props. when i debug it the props is undefined. and sometime the error is map undefined.
Here is my code
"ABOUT COMPONENT" about.tsx
enum Color {
Black = 'Black',
Red = 'Red'
}
type aboutProps = {
items: string,
backgroundColor: Color,
minimumHeight: number,
justify: string,
align: string,
fullWidth: boolean
}
const AboutComponent: FC<aboutProps> = ({items, backgroundColor, minimumHeight, justify, align,
fullWidth}: aboutProps) => { return (
<>
<aboutContainer>
<div>
{items.map(({ heading, url, openInNewWindow, fontColor }) => {
return (
<Text {...props}
fontColor={fontColor}
text={heading}
url={url}
openInNewWindow={openInNewWindow}
dangerouslySetInnerHTML={{ __html: heading }}/>
)
})}
</div>
</aboutContainer>
<>
)
};
export default AboutComponent;
"CONTACT COMPONENT"
contact.tsx
interface aboutProps {
items: string,
backgroundColor: Color,
minimumHeight: number,
justify: string,
align: string,
fullWidth: boolean
}
interface contactProps extends aboutProps {
phone?: number,
name?: string,
}
const ContactComponent: FC<contactProps> = ({items, backgroundColor, minimumHeight, justify, align, fullWidth, phone, name}: contactProps) => {
return (
<>
<AboutComponent items={items}
backgroundColor = {backgroundColor}
minimumHeight = {minimumHeight}
justify = {justify}
align = {align}
fullWidth = {fullWidth}/>
</>
)
};
export default ContactComponent;
The props is undefined such as items, background, minimumHeight, justify, align, fullWidth
It is a parent-child relationship. I don't know why you think it's not. ContactComponent
is the parent and AboutComponent
is the child.
ContactComponent
requires that it be called with all of the props of AboutComponent
and you are passing them down correctly. If you are getting errors that the props are undefined
then that problem isn't in the code you've posted here. It's that you are calling <ContactComponent/>
without the right props.
But there are a lot of other problems. The most glaring one is the prop items
-- your types say that it is a string
, but your code treats it as an array
of objects with properties { heading, url, openInNewWindow, fontColor }
. You need to either A) require that you have an array of these objects or B) use the children
prop and call your AboutComponent
with <Text/>
elements inside of it.
You don't want to use dangerouslySetInnerHTML
and you really don't need it. It doesn't do anything here unless your Text
component is taking this prop and using it. It looks like your Text
is already taking a text
prop so it can create its own HTML content.
You might want to make some of the style props optional. Right now they are all required.
This is my attempt to clean-up your components:
import React, { CSSProperties, FC } from "react";
export enum Color {
// CSS color names are lower-case
Black = "black",
Red = "red"
}
export type TextProps = {
text: string;
url: string;
openInNewWindow?: boolean;
fontColor?: CSSProperties["color"];
};
export const Text: FC<TextProps> = ({
text,
url,
openInNewWindow = false,
fontColor
}) => {
return (
<a
href={url}
target={openInNewWindow ? "_blank" : "_self"}
style={{ color: fontColor, display: "block", padding: 10 }}
>
{text}
</a>
);
};
export type AboutContainerProps = {
backgroundColor?: Color;
minimumHeight?: number;
justify?: string;
align?: string;
fullWidth?: boolean;
};
export const AboutContainer: FC<AboutContainerProps> = ({
backgroundColor = Color.Black,
minimumHeight,
justify = "space-evenly",
align = "center",
fullWidth = true,
children // the JSX children -- this prop is automatically included by FC
}) => {
return (
<div
style={{
background: backgroundColor,
minHeight: minimumHeight,
width: fullWidth ? "100%" : "auto",
display: "flex",
justifyContent: justify,
alignItems: align
}}
>
{children}
</div>
);
};
export type AboutProps = AboutContainerProps & {
items: TextProps[];
};
export const AboutComponent: FC<AboutProps> = ({
items,
...aboutProps // rest object for all other props
}: AboutProps) => {
return (
<AboutContainer {...aboutProps}>
{items.map((props) => {
return <Text key={props.text} {...props} />;
})}
</AboutContainer>
);
};
export type ContactInfo = {
phone?: number;
name?: string;
};
export const ContactInfoComponent: FC<ContactInfo> = ({ phone, name }) => {
if (!phone && !name) {
return null;
}
//TODO: format phone number string
return (
<div>
<h3>Get In Touch</h3>
{name && <div>{name}</div>}
{phone && <div>Call Me: {phone}</div>}
</div>
);
};
export type ContactProps = AboutProps & ContactInfo;
// do we really even need this component? can't we just compose it from the other two?
export const ContactComponent: FC<ContactProps> = ({
phone,
name,
...aboutProps
}) => {
return (
<div>
<ContactInfoComponent phone={phone} name={name} />
<AboutComponent {...aboutProps} />
</div>
);
};
With that sort of setup you call it like this, where items
is an array of props objects.
const Test = () => (
<ContactComponent
minimumHeight={100}
justify="flex-end"
align="center"
items={[
{
text: "Home",
url: "/"
},
{
text: "Facebook",
url: "some link",
openInNewWindow: true,
fontColor: Color.Red
}
]}
name={"My Name"}
phone={5555555555}
/>
);
This makes sense if the data is coming in a raw form from a database or API. But if you are writing out props yourself you probably want to call it using modular pieces:
const Test = () => (
<div>
<ContactInfoComponent name={"My Name"} phone={5555555555} />
<AboutContainer
minimumHeight={100}
justify="flex-end"
align="center"
fullWidth={false}
>
<Text url="/">Home</Text>
<Text url="some link" openInNewWindow={true} fontColor={Color.Red}>
Facebook
</Text>
</AboutContainer>
</div>
);
So you would make use of the children
prop rather than passing props down multiple levels.
import React, { CSSProperties, FC } from "react";
export enum Color {
// CSS color names are lower-case
Black = "black",
Red = "red"
}
export type TextProps = {
url: string;
openInNewWindow?: boolean;
fontColor?: CSSProperties["color"];
};
export const Text: FC<TextProps> = ({
children,
url,
openInNewWindow = false,
fontColor
}) => {
return (
<a
href={url}
target={openInNewWindow ? "_blank" : "_self"}
style={{ color: fontColor, display: "block", padding: 10 }}
>
{children}
</a>
);
};
export type AboutContainerProps = {
backgroundColor?: Color;
minimumHeight?: number;
justify?: string;
align?: string;
fullWidth?: boolean;
};
export const AboutContainer: FC<AboutContainerProps> = ({
backgroundColor = Color.Black,
minimumHeight,
justify = "space-evenly",
align = "center",
fullWidth = true,
children // the JSX children -- this prop is automatically included by FC
}) => {
return (
<div
style={{
background: backgroundColor,
minHeight: minimumHeight,
width: fullWidth ? "100%" : "auto",
display: "flex",
justifyContent: justify,
alignItems: align
}}
>
{children}
</div>
);
};
export type ContactInfo = {
phone?: number;
name?: string;
};
export const ContactInfoComponent: FC<ContactInfo> = ({ phone, name }) => {
if (!phone && !name) {
return null;
}
//TODO: format phone number string
return (
<div>
<h3>Get In Touch</h3>
{name && <div>{name}</div>}
{phone && <div>Call Me: {phone}</div>}
</div>
);
};
This code is mostly the same but we can actually delete a few of the components.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.