簡體   English   中英

使用 Ionic/React/Typescript 傳遞道具時出錯 - React.FC 中的道具錯誤<'wrong props here'>

[英]Error when passing props with Ionic/React/Typescript - Wrong props in React.FC<'wrong props here'>

在我沒有成功地解決這個問題之后。 我一直在檢查這里的許多問題,但我找不到適合我的情況,所以拜托,我想向你尋求幫助。

我在通過<WeatherCard/>組件傳遞道具時遇到問題。 測試應用程序有 2 個選項卡,並且兩個選項卡都呈現<WeatherCard/> 當我在 Tab1.tsx Typescript 中的 hover <WeatherCard/>向我顯示錯誤的(意外的)道具 (WeatherProps) 時,請參見下文:

     (alias) const WeatherCard: React.FC<WeatherProps>
import WeatherCard

另一方面,當我在 Tab2.tsx 中輸入 hover <WeatherCard/>時,它顯示正確的道具被傳遞,見下文:

         (alias) const WeatherCard: React.FC<WeatherCardProps>
 import WeatherCard

此外,它顯示以下錯誤:

[react-scripts] TS2322: 類型 '{ weatherIconUrl: string; 天氣數據:任何; 天氣變量:字符串[]; }' 不可分配給類型 'IntrinsicAttributes & WeatherProps & { children?: ReactNode; }'。 [react-scripts] 類型 'IntrinsicAttributes & WeatherProps & { children?: ReactNode; 上不存在屬性 'weatherIconUrl' }'。

我 console.log 在<WeatherProperty/>中傳遞的道具,這些道具實際上是傳遞給<WeatherCard/>的道具,因此,似乎出於某種原因,在使用 Tab1 時未考慮在<WeatherProperty/>中聲明的道具

我將包括以下代碼:

Tab1.tsx

import {
  IonButton,
  IonButtons,
  IonCard,
  IonCardContent,
  IonCol,
  IonContent,
  IonGrid,
  IonHeader,
  IonItem,
  IonPage,
  IonRow,
  IonText,
  IonThumbnail,
  IonTitle,
  IonToolbar,
  IonLoading,
  IonAlert,
} from "@ionic/react";
import styles from "./Tab1.module.css";
import { RefreshOutline } from "react-ionicons";
import { Geolocation } from "@capacitor/geolocation";
import React, { useEffect } from "react";
import { RootState } from "../app/store";
import { useDispatch, useSelector } from "react-redux";
import { useGetCurrentPositionWeatherQuery } from "../services/weather";
import { setQueryCoord } from "../app/coordQuerySlice";
import TestSkeleton from "../components/TestSkeleton";
import WeatherCard from "../components/WeatherProperty";

const Tab1: React.FC = () => {
  const dispatch = useDispatch();
  const coordQueryState = useSelector((state: RootState) => state.coordQuery);
  const {
    refetch,
    data: weatherData,
    isFetching,
    isError,
  } = useGetCurrentPositionWeatherQuery(
    {
      lat: coordQueryState.lat,
      lon: coordQueryState.lon,
      appid: "cd555b96865912ac5781d36d6d7de140",
      units: "metric",
    },
    { skip: coordQueryState.skip }
  );

  const setCurrentPosition = async () => {
    const data = await Geolocation.getCurrentPosition();
    const {
      coords: { latitude: latFetched },
      coords: { longitude: lonFetched },
    } = data;
    dispatch(setQueryCoord({ lat: latFetched, lon: lonFetched, skip: false }));
  };

  useEffect(() => {
    setCurrentPosition();
  }, []);

  function refreshCurrentPositionHandler() {
    refetch();
  }

  if (weatherData) {
    console.log(weatherData);
  }

  const weatherIconUrl = weatherData
    ? `https://openweathermap.org/img/wn/${weatherData.weather[0].icon}@2x.png`
    : undefined;
  const weatherVars = weatherData ? Object.keys(weatherData.main) : undefined;

  return (
    <IonPage>
      <IonHeader>
        <IonToolbar className={styles["ion-toolbar-dashboard"]}>
          <IonTitle className="ion-margin-bottom" size="large">
            Dashboard
          </IonTitle>
          <IonButtons slot="end">
            <IonButton>
              <RefreshOutline
                onClick={refreshCurrentPositionHandler}
                color={"black"}
                height="35px"
                width="35px"
                cssClasses={styles.refreshOutline}
              />
            </IonButton>
          </IonButtons>
        </IonToolbar>
      </IonHeader>
      <IonContent fullscreen>
        <IonGrid className="ion-no-margin">
          <IonRow style={{ margin: "10px" }}>
            <IonCol className="ion-text-center">
              <h1 style={{ fontSize: "20px" }}>
                Here's your location based weather
              </h1>
            </IonCol>
          </IonRow>
        </IonGrid>
        {!weatherData && <IonLoading isOpen={!weatherData} />}
        {isFetching && !weatherData && <IonLoading isOpen={isFetching} />}
        {isError && <IonAlert isOpen={isError} />}
        {!isFetching && weatherData && (
          <WeatherCard
            weatherIconUrl={weatherIconUrl as string} \\problem is indeed here
            weatherData={weatherData}
            weatherVars={weatherVars as string[]}
          />
        )}
      </IonContent>
    </IonPage>
  );
};

export default Tab1;

Tab2.tsx

import {
  IonContent,
  IonHeader,
  IonPage,
  IonTitle,
  IonToolbar,
} from "@ionic/react";
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setQueryCity } from "../app/cityQuerySlice";
import { RootState } from "../app/store";
import WeatherCard from "../components/WeatherCard";
import { useGetWeatherByCityQuery } from "../services/weather";
import styles from "./Tab1.module.css";

const Tab2: React.FC = () => {
  const dispatch = useDispatch();
  const cityQueryState = useSelector((state: RootState) => state.cityQuery);
  const {
    refetch,
    data: weatherData,
    isFetching,
    isError,
  } = useGetWeatherByCityQuery(
    {
      q: cityQueryState.city,
      appid: "cd555b96865912ac5781d36d6d7de140",
      units: "metric",
    },
    { skip: cityQueryState.skip }
  );

  useEffect(() => {
    dispatch(setQueryCity({ city: "London", skip: false }));
  }, [dispatch]);

  const weatherIconUrl = weatherData
    ? `https://openweathermap.org/img/wn/${weatherData.weather[0].icon}@2x.png`
    : undefined;
  const weatherVars = weatherData ? Object.keys(weatherData.main) : undefined;

  return (
    <IonPage>
      <IonHeader>
        <IonToolbar className={styles["ion-toolbar-dashboard"]}>
          <IonTitle className="ion-margin-bottom" size="large">
            Search
          </IonTitle>
        </IonToolbar>
      </IonHeader>
      <IonContent fullscreen>
        {!weatherData && <p>weather data is loading</p>}
        {weatherData && (
          <WeatherCard
            weatherData={weatherData} \\ and here the props are passed properly...
            weatherIconUrl={weatherIconUrl as string}
            weatherVars={weatherVars as string[]}
          />
        )}
      </IonContent>
    </IonPage>
  );
};

export default Tab2;

天氣卡.tsx

import {
  IonCard,
  IonCardContent,
  IonGrid,
  IonRow,
  IonCol,
  IonText,
} from "@ionic/react";
import { useEffect } from "react";
import WeatherProperty from "./WeatherProperty";

interface WeatherCardProps {
  weatherIconUrl: string;
  weatherVars: string[];
  weatherData: any;
}

const WeatherCard: React.FC<WeatherCardProps> = (props: WeatherCardProps) => {
  const { weatherVars, weatherData, weatherIconUrl } = props;

  console.log(weatherData);
  console.log(weatherData);
  console.log(weatherIconUrl);

  useEffect(() => {
    console.log("component WeatherCard mounted");
  });

  return (
    <IonCard>
      <IonCardContent>
        <IonGrid>
          <IonRow>
            <IonCol class="ion-text-center">
              <IonText color="primary">
                <h1 style={{ marginBottom: "0px", display: "inline" }}>
                  {weatherData.name},
                  <span style={{ color: "grey" }}>
                    {" "}
                    {weatherData.sys.country === "JP"
                      ? "Japan"
                      : "Outside Japan"}
                  </span>
                </h1>
              </IonText>
            </IonCol>
          </IonRow>
          <IonRow className="ion-justify-content-center ion-align-items-center">
            <IonCol size="auto">
              <img
                style={{
                  width: "70px",
                  height: "70px",
                  display: "inline",
                }}
                src={weatherIconUrl}
              />
            </IonCol>
            <IonCol size="auto" className="ion-justify-content-center">
              <h1
                style={{
                  display: "inline",
                  fontSize: "18px",
                }}
              >
                {weatherData.weather[0].description}
              </h1>
            </IonCol>
          </IonRow>
          <IonRow>
            <IonCol>
              <WeatherProperty
                main={weatherVars[1]}
                mainValue={weatherData.main[weatherVars[1]]}
              />
            </IonCol>
            <IonCol>
              <WeatherProperty
                main={weatherVars[2]}
                mainValue={weatherData.main[weatherVars[2]]}
              />
            </IonCol>
          </IonRow>
          <IonRow>
            <IonCol>
              <WeatherProperty
                main={weatherVars[3]}
                mainValue={weatherData.main[weatherVars[3]]}
              />
            </IonCol>
            <IonCol>
              <WeatherProperty
                main={weatherVars[5]}
                mainValue={weatherData.main[weatherVars[5]]}
              />
            </IonCol>
          </IonRow>
        </IonGrid>
      </IonCardContent>
    </IonCard>
  );
};

export default WeatherCard;

WeatherProperty.tsx

import { IonItem, IonLabel, IonText, IonThumbnail } from "@ionic/react";
import { useEffect } from "react";
import "./WeatherProperty.module.css";

interface WeatherProps {
  main: string;
  mainValue: number;
}

const WeatherProperty: React.FC<WeatherProps> = (props: WeatherProps) => {
  console.log(`these are the props in WeatherProperty component`);
  console.log(props);

  let propMod;
  let unit;
  let fileName;
  if (props.main === "feels_like") {
    propMod = "It feels like:";
    unit = "deg";
    fileName = "feels-like.png";
  }
  if (props.main === "temp_min") {
    propMod = "Minimum temperature:";
    unit = "deg";
    fileName = "temp-min.png";
  }
  if (props.main === "temp_max") {
    propMod = "Maximum temperature:";
    unit = "deg";
    fileName = "temp-max.png";
  }
  if (props.main === "humidity") {
    propMod = "Humidity:";
    unit = "%";
    fileName = "humidity.png";
  }
  useEffect(() => {
    console.log("component WeatherProperty mounted");
  });

  return (
    <IonItem lines="none">
      <IonThumbnail slot="start" className="weather-icons">
        <img src={`${window.location.origin}/assets/${fileName}`} />
      </IonThumbnail>
      <IonLabel slot="">
        <IonText color="primary">
          <h1 style={{ fontSize: "15px" }}>{propMod}</h1>
        </IonText>
        <h2>{`${Math.trunc(props.mainValue)} ${unit}`}</h2>
      </IonLabel>
    </IonItem>
  );
};

export default WeatherProperty;

您需要修復兩件事:

  1. 從錯誤的組件導入

Tab1.tsx

import WeatherCard from "../components/WeatherProperty";

// Maybe the correct one is "WeatherCard" ?
// import WeatherCard from "../components/WeatherCard";
  1. 為道具分配了錯誤的類型定義

天氣卡.tsx

const WeatherProperty: React.FC<WeatherProps> = (props: WeatherProps) => {

// you can just omit the prop's type 
// (props) => { 
// 
// or use object destructuring for the convenience
// ({ weatherData, weatherVar, weatherIconUrl }) => {

暫無
暫無

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

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