After dealing with this problem for good while I got no success. I have been checking many questions around here but I could not find one that suits my case, so please, I would like to ask you for help.
I have a problem passing my props through the <WeatherCard/>
component. The test application has 2 tabs and both tabs have the <WeatherCard/>
being rendered.
When I hover <WeatherCard/>
in Tab1.tsx Typescript shows me the wrong (unexpected) props (WeatherProps), see below:
(alias) const WeatherCard: React.FC<WeatherProps>
import WeatherCard
On the other hand, whereas when I hover <WeatherCard/>
in Tab2.tsx it shows the correct props being passed, see below:
(alias) const WeatherCard: React.FC<WeatherCardProps>
import WeatherCard
Moreover it shows the following error:
[react-scripts] TS2322: Type '{ weatherIconUrl: string; weatherData: any; weatherVars: string[]; }' is not assignable to type 'IntrinsicAttributes & WeatherProps & { children?: ReactNode; }'. [react-scripts] Property 'weatherIconUrl' does not exist on type 'IntrinsicAttributes & WeatherProps & { children?: ReactNode; }'.
I console.log the props passed in <WeatherProperty/>
and these props are actually the props passed to <WeatherCard/>
so, it seems like for some reason the props declared in
<WeatherProperty/>
are not taken into account when using Tab1
I will include the code below:
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;
WeatherCard.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 >
<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;
CodePudding user response:
There are two things you need to fix:
- Imported from the wrong component
Tab1.tsx
import WeatherCard from "../components/WeatherProperty";
// Maybe the correct one is "WeatherCard" ?
// import WeatherCard from "../components/WeatherCard";
- Assigned the wrong type definition for props
WeatherCard.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 }) => {