如何修复onChange事件以获得event.target.value



我有下面的代码,在验证实现(useForm、yupResolver和Yup(之前,handleChange函数运行得很好。如果我console.log值变量,我将一无所获。它似乎没有记录我在输入字段中键入的内容。此外,我在浏览器上收到以下错误:

Uncaught (in promise) TypeError: event.preventDefault is not a function
at executeSearch (index.tsx:64:1)
at createFormControl.ts:1045:1

我该怎么解决这个问题?对不起,我对TypeScript和React比较陌生。

import React, { useState, useEffect, FormEventHandler } from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import Loader from "react-ts-loaders";
import { WeatherApiVariables } from "../../../variables";
import { inputSchema } from "../../../validations/schema";
import lowTemperature from "../../../assets/icons/low-temperature-icon.svg";
import highTemperature from "../../../assets/icons/high-temperature-icon.svg";
import styles from "./weather-api.module.scss";
export function WeatherApi() {
const [cityName, setCityName] = useState<string>("");
const [cityWeather, setCityWeather]: any = useState<{}>({});
const [cityWeatherForecast, setCityWeatherForecast]: any = useState<[]>([]);
const [value, setValue] = useState("");
const [loading, setLoading] = useState<boolean>(false);
const {
register,
handleSubmit,
formState: { errors },
}: any = useForm({
resolver: yupResolver(inputSchema),
});
async function getCurrentWeather(cityName: string): Promise<any> {
setLoading(true);
const response = await fetch(
`https://api.weatherapi.com/v1/current.json?key=${WeatherApiVariables.token}&q=${cityName}&${WeatherApiVariables.airQuality}&${WeatherApiVariables.dataLanguage}`
);
const data = await response.json();
return data;
}
async function getWeatherForecast(cityName: string): Promise<any> {
setLoading(true);
const response = await fetch(
`https://api.weatherapi.com/v1/forecast.json?key=${WeatherApiVariables.token}&q=${cityName}&${WeatherApiVariables.airQuality}&${WeatherApiVariables.dataLanguage}&days=${WeatherApiVariables.forecastDays}`
);
const data = await response.json();
return data;
}
useEffect(() => {
async function fetchData() {
const currentWeather = await getCurrentWeather(cityName);
const weatherForecast = await getWeatherForecast(cityName);
setCityWeather(currentWeather);
setCityWeatherForecast(weatherForecast);
setLoading(false);
}
fetchData();
}, [cityName]);
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value);
console.log(value);
};
const executeSearch: FormEventHandler<HTMLFormElement> = (
event: React.FormEvent<HTMLFormElement>
) => {
event.preventDefault();
const transformedText = value
.normalize("NFD")
.replace(/[u0300-u036f]/g, "");
setCityName(transformedText);
setValue("");
};
return (
<section className={styles.main}>
<div className={styles.search_container}>
<h2>Busque por uma cidade</h2>
<form
onSubmit={handleSubmit(executeSearch)}
className={styles.search_form}
>
<input
type="text"
name="searchField"
onChange={handleChange}
placeholder="Ex: Blumenau, Santa Catarina"
{...register("searchField")}
/>
<p>{errors.searchField?.message}</p>
<input
type="submit"
className={styles.search_btn}
value="Pesquisar"
/>
</form>
</div>
<div className={styles.current_weather_section}>
{loading ? (
<Loader className="loader" type="roller" size={150} />
) : (
<>
{!cityWeather.location ? (
""
) : (
<div className={styles.current_weather_container}>
<h2> Condição climática atual em:</h2>
<h3>
{cityWeather.location.name}, {cityWeather.location.region}
</h3>
<div className={styles.condition_container}>
<span>{cityWeather.current.condition.text}</span>
<img
alt="ícone da condição atual do tempo"
src={cityWeather.current.condition.icon}
></img>
</div>
<span>Temperatura atual: {cityWeather.current.temp_c} °C</span>
<span>
Sensação térmica: {cityWeather.current.feelslike_c} °C
</span>
</div>
)}
</>
)}
</div>
{!cityWeatherForecast.forecast ? (
""
) : (
<>
<h2>Previsão para os próximos dias</h2>
<section className={styles.weather_forecast_section}>
{cityWeatherForecast.forecast.forecastday.map(
(item: any, key: string) => {
const dateUnix = (item.date_epoch + 86400) * 1000;
const newDate = new Date(dateUnix);
const forecastWeekDay = newDate.toLocaleString("pt-BR", {
weekday: "long",
});
const forecastDay = newDate.toLocaleString("pt-BR", {
day: "numeric",
});
return (
<ul key={key} className={styles.weather_forecast_list}>
<li>
<h2>
{forecastWeekDay} - {forecastDay}
</h2>
<div className={styles.forecast_condition_container}>
<span>{item.day.condition.text}</span>
<img
alt="ícone do clima"
src={item.day.condition.icon}
/>
</div>
<p>
Poss. chuva: {item.day.daily_chance_of_rain} % -{" "}
{item.day.totalprecip_mm} mm
</p>
<p>
<img
src={lowTemperature}
alt="termômetro - temperatura baixa"
/>
{item.day.mintemp_c} °C
</p>
<p>
<img
src={highTemperature}
alt="termômetro - temperatura alta"
/>
{item.day.maxtemp_c} °C
</p>
</li>
</ul>
);
}
)}
</section>
</>
)}
</section>
);
}

错误发生在executeSearch函数上,这是因为您将该函数与useForm道具handleSubmit一起使用。如果您查看文档,handleSubmit函数接受另一个具有三个参数的函数数据(这是您要为表单提供的表单结构形状(错误(有一个包含错误表单项的对象(和事件对象(有所有事件信息(:

((data: Object, e?: Event) => void, (errors: Object, e?: Event) => void) => Function

这意味着executeSearch函数使用数据对象作为事件,所以它不是实际的事件本身,而是formData。您可能不需要event.preventDefault(),因为react hook表单会为您处理这个问题,如果您想将事件用于其他事情,则必须使用正确的参数,如

const executeSearch = (
_data,
_errors,
event
) => {
event.preventDefault();
const transformedText = value
.normalize("NFD")
.replace(/[u0300-u036f]/g, "");
setCityName(transformedText);
setValue("");
};

我强烈建议阅读react hook表单的TS文档,一旦你习惯了它,你就不想再自己做表单了。

https://react-hook-form.com/ts

此外,这对你来说非常困惑,我还建议阅读TS文档,更好地了解类型和接口,这样你就可以按照预期使用react hook形式,并将自己的接口和类型与之结合使用。

https://www.typescriptlang.org/docs/handbook/typescript-tooling-in-5-minutes.html#interfaces

我找到了正确的方法:

import { useState, useEffect } from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import Loader from "react-ts-loaders";
import { WeatherApiVariables } from "../../../variables";
import { inputSchema } from "../../../validations/schema";
import lowTemperature from "../../../assets/icons/low-temperature-icon.svg";
import highTemperature from "../../../assets/icons/high-temperature-icon.svg";
import styles from "./weather-api.module.scss";
interface ISearch {
searchField: string;
}
export function WeatherApi() {
const [cityName, setCityName] = useState<string>("");
const [cityWeather, setCityWeather]: any = useState<{}>({});
const [cityWeatherForecast, setCityWeatherForecast]: any = useState<[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const {
register,
resetField,
handleSubmit,
formState: { errors },
}: any = useForm({
resolver: yupResolver(inputSchema),
});
async function getCurrentWeather(cityName: string): Promise<any> {
setLoading(true);
const response = await fetch(
`https://api.weatherapi.com/v1/current.json?key=${WeatherApiVariables.token}&q=${cityName}&${WeatherApiVariables.airQuality}&${WeatherApiVariables.dataLanguage}`
);
const data = await response.json();
return data;
}
async function getWeatherForecast(cityName: string): Promise<any> {
setLoading(true);
const response = await fetch(
`https://api.weatherapi.com/v1/forecast.json?key=${WeatherApiVariables.token}&q=${cityName}&${WeatherApiVariables.airQuality}&${WeatherApiVariables.dataLanguage}&days=${WeatherApiVariables.forecastDays}`
);
const data = await response.json();
return data;
}
useEffect(() => {
async function fetchData() {
const currentWeather = await getCurrentWeather(cityName);
const weatherForecast = await getWeatherForecast(cityName);
setCityWeather(currentWeather);
setCityWeatherForecast(weatherForecast);
setLoading(false);
}
fetchData();
}, [cityName]);
const handleSearch = (data: ISearch) => {
const transformedText = data.searchField
.normalize("NFD")
.replace(/[u0300-u036f]/g, "");
setCityName(transformedText);
resetField("searchField");
};
return (
<section className={styles.main}>
<div className={styles.search_container}>
<h2>Busque por uma cidade</h2>
<form
onSubmit={handleSubmit(handleSearch)}
className={styles.search_form}
>
<input
type="text"
name="searchField"
placeholder="Ex: Blumenau, Santa Catarina"
{...register("searchField")}
/>
<p>{errors.searchField?.message}</p>
<input
type="submit"
className={styles.search_btn}
value="Pesquisar"
/>
</form>
</div>
<div className={styles.current_weather_section}>
{loading ? (
<Loader className="loader" type="roller" size={150} />
) : (
<>
{!cityWeather.location ? (
""
) : (
<div className={styles.current_weather_container}>
<h2> Condição climática atual em:</h2>
<h3>
{cityWeather.location.name}, {cityWeather.location.region}
</h3>
<div className={styles.condition_container}>
<span>{cityWeather.current.condition.text}</span>
<img
alt="ícone da condição atual do tempo"
src={cityWeather.current.condition.icon}
></img>
</div>
<span>Temperatura atual: {cityWeather.current.temp_c} °C</span>
<span>
Sensação térmica: {cityWeather.current.feelslike_c} °C
</span>
</div>
)}
</>
)}
</div>
{!cityWeatherForecast.forecast ? (
""
) : (
<>
<h2>Previsão para os próximos dias</h2>
<section className={styles.weather_forecast_section}>
{cityWeatherForecast.forecast.forecastday.map(
(item: any, key: string) => {
const dateUnix = (item.date_epoch + 86400) * 1000;
const newDate = new Date(dateUnix);
const forecastWeekDay = newDate.toLocaleString("pt-BR", {
weekday: "long",
});
const forecastDay = newDate.toLocaleString("pt-BR", {
day: "numeric",
});
return (
<ul key={key} className={styles.weather_forecast_list}>
<li>
<h2>
{forecastWeekDay} - {forecastDay}
</h2>
<div className={styles.forecast_condition_container}>
<span>{item.day.condition.text}</span>
<img
alt="ícone do clima"
src={item.day.condition.icon}
/>
</div>
<p>
Poss. chuva: {item.day.daily_chance_of_rain} % -{" "}
{item.day.totalprecip_mm} mm
</p>
<p>
<img
src={lowTemperature}
alt="termômetro - Temperatura baixa"
/>
{item.day.mintemp_c} °C
</p>
<p>
<img
src={highTemperature}
alt="termômetro - Temperatura alta"
/>
{item.day.maxtemp_c} °C
</p>
</li>
</ul>
);
}
)}
</section>
</>
)}
</section>
);
}

最新更新