繁体   English   中英

如何传递来自不同组件(关于和联系)的道具? 不是父母对孩子。 使用反应 typescript

[英]How to pass props from different component(about and contact)? not parent to child. Using react typescript

我试图重用 about 组件来联系组件。 但我无法使用道具传递数据。 当我调试它时,道具是未定义的。 有时错误是 map 未定义。

这是我的代码

“关于组件” 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;

道具未定义,例如项目、背景、最小高度、对齐、对齐、全宽

一种父子关系。 我不知道你为什么认为它不是。 ContactComponent是父组件, AboutComponent是子组件。

ContactComponent要求使用AboutComponent的所有道具调用它,并且您正确地传递它们。 如果您收到道具undefined的错误,那么该问题不在您在此处发布的代码中。 这是您在没有正确道具的情况下调用<ContactComponent/>


但是还有很多其他的问题。 最明显的是道具items ——您的类型说它是一个string ,但您的代码将其视为具有属性{ heading, url, openInNewWindow, fontColor }的对象array 您需要 A) 要求您拥有这些对象的数组或 B) 使用children道具并在其中调用带有<Text/>元素的AboutComponent

你不想使用dangerouslySetInnerHTML的SetInnerHTML,你真的不需要它。 除非您的Text组件正在使用此道具并使用它,否则它不会在这里做任何事情。 看起来您的Text已经在使用text道具,因此它可以创建自己的 HTML 内容。

您可能希望将一些样式道具设为可选。 现在它们都是必需的。

这是我清理组件的尝试:

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>
  );
};

代码沙盒链接

通过这种设置,您可以这样称呼它,其中items是 props 对象的数组。

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}
  />
);

如果数据以原始形式来自数据库或 API,这很有意义。 但是,如果您自己编写道具,您可能希望使用模块化部件来调用它:

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>
);

因此,您将使用children道具,而不是将道具向下传递多个级别。

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>
  );
};

这段代码基本相同,但我们实际上可以删除一些组件。

代码沙盒链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM