簡體   English   中英

如何定義類型的任何屬性子項? typescript

[英]How to define type any of property children? typescript

我正在用 React 研究 Typescript 我有 Team Page 和一個 slider 組件,該組件工作得很好,但我想定義孩子的類型。

團隊頁面

import react, { Fragment, useEffect, useState } from "react";
import { Container, Row, Button, Col } from "react-bootstrap";
import Slider from "./components/Slider";

const SliderProps = {
  zoomFactor: 30, // How much the image should zoom on hover in percent
  slideMargin: 10, // Margin on each side of slides
  maxVisibleSlides: 5,
  pageTransition: 500, // Transition time when flipping pages
};

export interface PlayerList {
  players: {
    name: string;
    username: string;
  }[];
}

const TeamPage: React.FC = () => {
  const playerList = {
    players: [
      {
        name: "Exon",
        username: "p_exon",
      },
      {
        name: "Nolan",
        username: "p_nolan",
      },
      {
        name: "T Mac",
        username: "p_tmac",
      },
      {
        name: "Warren",
        username: "p_warren",
      },
    ],
  };

  if (playerList.players.length < 1) return <div>Loading </div>;

  return (
    <Container fluid p-0>
      <Row>
        <Col md={{ span: 7, offset: 2 }}>
          <h2>Player List</h2>
        </Col>
      </Row>
      <Row>
        <Col>
          <Slider {...SliderProps}>
            {playerList.players.map((PlayerList) => (
              <div key={PlayerList.name}>
                <img
                  src="https://st.depositphotos.com/2101611/3925/v/600/depositphotos_39258143-stock-illustration-businessman-avatar-profile-picture.jpg"
                  alt="xd"
                />
                <>{PlayerList.name}</>
              </div>
            ))}
          </Slider>
        </Col>
      </Row>
    </Container>
  );
};
export default TeamPage;

和一個 Slider 組件

import React, { useState, useEffect, useRef } from "react";
import SliderItem from "./SliderItem";
import { StyledSliderWrapper, StyledSlider } from "./SliderStyles";

type SliderProps = {
  children?: any;
  zoomFactor: number;
  slideMargin: number;
  maxVisibleSlides: number;
  pageTransition: number;
};

const numberOfSlides = (maxVisibleSlides: number, windowWidth: number) => {
  if (windowWidth > 1200) return maxVisibleSlides;
  if (windowWidth > 992) return 4;
  if (windowWidth > 768) return 3;
  return 2;
};

const Slider: React.FC<SliderProps> = ({
  children,
  zoomFactor,
  slideMargin,
  maxVisibleSlides,
  pageTransition,
}) => {
  const [currentPage, setCurrentPage] = useState(0);
  const [transformValue, setTransformValue] = useState(`-${zoomFactor / 2}%`);
  const [scrollSize, setScrollSize] = useState(0);

  const sliderRef = useRef<HTMLElement>(null!);

  const visibleSlides = numberOfSlides(maxVisibleSlides, scrollSize);

  const totalPages: number = Math.ceil(children.length / visibleSlides) - 1;

  useEffect(() => {
    const resizeObserver = new ResizeObserver((entries) => {
      setScrollSize(entries[0].contentRect.width);
    });
    resizeObserver.observe(sliderRef.current);
  }, [sliderRef]);

  useEffect(() => {
    if (sliderRef && sliderRef.current) {
      if (currentPage > totalPages) setCurrentPage(totalPages);
      sliderRef.current.style.transform = `translate3D(-${
        currentPage * scrollSize
      }px, 0, 0)`;
    }
  }, [sliderRef, currentPage, scrollSize, totalPages]);

  const disableHoverEffect = () => {
    if (sliderRef.current) sliderRef.current.style.pointerEvents = "none";
    setTimeout(() => {
      if (sliderRef.current) sliderRef.current.style.pointerEvents = "all";
    }, pageTransition);
  };

  const handleSlideMove = (forward: boolean) => {
    disableHoverEffect();
    setCurrentPage(currentPage + (forward ? 1 : -1));

    if (sliderRef.current)
      sliderRef.current.style.transform = `translate3D(-${
        (currentPage + (forward ? 1 : -1)) * scrollSize
      }px, 0, 0)`;
  };

  const handleMouseOver = (id: number) => {
    if (id % visibleSlides === 1) setTransformValue("0%");
    if (id % visibleSlides === 0) setTransformValue(`-${zoomFactor}%`);
  };

  const handleMouseOut = () => {
    setTransformValue(`-${zoomFactor / 2}%`);
  };

  const assignSlideClass = (index: number, visibleSlides2: number) => {
    const classes = ["right", "left"];
    return classes[index % visibleSlides2] || "";
  };

  return (
    <StyledSliderWrapper zoomFactor={zoomFactor} visibleSlides={visibleSlides}>
      <StyledSlider
        visibleSlides={visibleSlides}
        transformValue={transformValue}
        zoomFactor={zoomFactor}
        slideMargin={slideMargin}
        pageTransition={pageTransition}
        ref={sliderRef}
      >
        {children.map((child: any, i: any) => (
          <SliderItem
            key={i}
            slideMargin={slideMargin}
            visibleSlides={visibleSlides}
            zoomFactor={zoomFactor}
            slideClass={assignSlideClass(i + 1, visibleSlides)}
            id={i + 1}
            callback={handleMouseOver}
            callbackOut={handleMouseOut}
          >
            {child}
          </SliderItem>
        ))}
      </StyledSlider>
      {currentPage > 0 && (
        <div className="button-wrapper back">
          <button
            className="button back"
            onClick={() => handleSlideMove(false)}
          >
            &#8249;
          </button>
        </div>
      )}
      {currentPage !== totalPages && (
        <div className="button-wrapper forward">
          <button
            className="button forward"
            onClick={() => handleSlideMove(true)}
          >
            &#8250;
          </button>
        </div>
      )}
    </StyledSliderWrapper>
  );
};

export default Slider;

我想澄清該組件的工作原理,我已經嘗試過 React.ReactNode 和 reactElement 類型但我似乎無法實現它,我也嘗試將孩子定義為 PlayerList 接口但是當我使用...SliderProps on teampage <Slider {...SliderProps}>類型不匹配,我收到此錯誤。 'Element[]' 類型中缺少屬性 'players',但在 'PlayerList' 類型中是必需的。

如果孩子的類型發生變化,我認為 slider 組件上的這條線

const totalPages: number = Math.ceil(children.length / visibleSlides) - 1;

而 slider 組件上的這一行必須更改

{children.map((child: any, i: any) => (
          <SliderItem
            key={i}
            slideMargin={slideMargin}
            visibleSlides={visibleSlides}
            zoomFactor={zoomFactor}
            slideClass={assignSlideClass(i + 1, visibleSlides)}
            id={i + 1}
            callback={handleMouseOver}
            callbackOut={handleMouseOut}
          >
            {child}
          </SliderItem>

我還希望避免 object 可能是 null 或未定義。 將不勝感激解釋。

children確實應該被聲明為children?: React.ReactNode; .

type SliderProps = {
  children?: React.ReactNode;
  zoomFactor: number;
  slideMargin: number;
  maxVisibleSlides: number;
  pageTransition: number;
};

現在,要獲得給定的計數和 map 到每個孩子,您必須使用React.Children實用程序 class。 獲取計數將如下所示:

const totalPages: number = Math.ceil(React.Children.count(children) / visibleSlides) - 1;

對於 map:

{ React.Children.map(children, (child, i) => (
  <SliderItem
    key={i}
    slideMargin={slideMargin}
    visibleSlides={visibleSlides}
    zoomFactor={zoomFactor}
    slideClass={assignSlideClass(i + 1, visibleSlides)}
    id={i + 1}
    callback={handleMouseOver}
    callbackOut={handleMouseOut}
  >
    {child}
  </SliderItem>
))}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM