I am trying to learn React and Typescript. I am building a little demo app that sends a request to the api
How can I get this to work the way I want it to? Any help would be much appreciated. If a moderator deletes this question, can they please let me know why? Thanks.
import React, {FormEvent, useEffect, useState} from "react";
import { useForm } from 'react-hook-form'
import "./App.css";
import axios from "axios";
import { IPlace } from "./IPlace";
export default function App2(){
const [placeFound, setPlaceFound] = useState<IPlace[]>([]);
const [zipSearch, setZipSearch] = useState("");
const [errorFound, setErrorFound] = React.useState("");
const renderPlaces = () => {
console.log("Render places runs")
if(placeFound.length !== 0){
return (<div className="table-container">
<table>
<thead>
<tr>
<th><span>State</span></th>
<th><span>Longitude</span></th>
<th><span>Latitude</span></th>
<th><span>Place Name</span></th>
</tr>
</thead>
{placeFound.map((place) =>{
return (
<tbody>
<tr>
<td>{place.state}</td>
<td>{place.longitude}</td>
<td>{place.latitude}</td>
<td>{place["place name"]}</td>
</tr>
</tbody>
)})}
</table>
</div>)
}
}
React.useEffect(() => {
console.log("useEffect is run")
const query = encodeURIComponent(zipSearch);
axios
.get(`https://api.zippopotam.us/us/${query}`,{
})
.then((response) => {
setPlaceFound(response.data.places);
setErrorFound("");
})
.catch((ex) => {
let errorFound = axios.isCancel(ex)
? 'Request Cancelled'
: ex.code === 'ECONNABORTED'
? 'A timeout has occurred'
: ex.response.status === 404
? 'Resource Not Found'
: 'An unexpected error has occurred';
setErrorFound(ex.code);
setPlaceFound([]);
});
}
},[zipSearch]);
const search=(event: FormEvent<HTMLFormElement>) =>{
console.log("Search method runs")
event.preventDefault();
const form = event.target as HTMLFormElement;
const input = form.querySelector('#zipSearchInput') as HTMLInputElement;
setZipSearch(input.value);
}
return (
<div className="App">
<div className="search-container">
<h1>Place Search using Zip Code</h1>
<form className="searchForm" onSubmit={event => search(event)}>
<div>
<label htmlFor="zipSearchInput">Zip Code</label>
<input {...register('zipSearchInput', { required: true, minLength: 5, maxLength: 5 }) }
id="zipSearchInput"
name="zipSearchInput"
type="text"
/>
</div>
{
errors.zipSearchInput && <div className="error">Zip Code is required and must be 5 digits long</div>
}
<button type="submit">Search</button>
</form>
</div>
{placeFound.length !== 0 && renderPlaces()}
{errorFound !== "" && <p className="error">{errorFound}</p>}
</div>)
}
CodePudding user response:
What you should probably do is actually use the library above react-hook-form
and its functions.
Then I believe that the useEffect that you are using is pretty useless in this scenario, You are going the long way for a simpler task. You can simply call the api on submit of the form and get rid of the state zipSearch
the react-hook-form
is taking care of that for you.
Here's the fixed version of the code below:
import React, { useState } from "react";
import { FormProvider, useForm } from "react-hook-form";
import axios from "axios";
interface IPlace {
state: string;
longitude: string;
latitude: string;
"place name": string;
}
export default function App2() {
const [placeFound, setPlaceFound] = useState<IPlace[]>([]);
const [errorFound, setErrorFound] = React.useState("");
const formMethods = useForm<{ zipSearchInput: string }>();
const renderPlaces = () => {
console.log("Render places runs");
if (placeFound.length !== 0) {
return (
<div className="table-container">
<table>
<thead>
<tr>
<th>
<span>State</span>
</th>
<th>
<span>Longitude</span>
</th>
<th>
<span>Latitude</span>
</th>
<th>
<span>Place Name</span>
</th>
</tr>
</thead>
{placeFound.map((place) => {
console.log(place);
return (
<tbody key={place.latitude}>
<tr>
<td>{place.state}</td>
<td>{place.longitude}</td>
<td>{place.latitude}</td>
<td>{place["place name"]}</td>
</tr>
</tbody>
);
})}
</table>
</div>
);
}
};
const search = (values: { zipSearchInput: string }) => {
console.log(values);
const query = encodeURIComponent(values.zipSearchInput);
axios
.get(`https://api.zippopotam.us/us/${query}`, {})
.then((response) => {
setPlaceFound(response.data.places);
setErrorFound("");
})
.catch((ex) => {
let _errorFound = axios.isCancel(ex)
? "Request Cancelled"
: ex.code === "ECONNABORTED"
? "A timeout has occurred"
: ex.response.status === 404
? "Resource Not Found"
: "An unexpected error has occurred";
setErrorFound(_errorFound);
setPlaceFound([]);
});
};
return (
<div className="App">
<div className="search-container">
<h1>Place Search using Zip Code</h1>
<FormProvider {...formMethods}>
<form className="searchForm" onSubmit={formMethods.handleSubmit(search)}>
<div>
<label htmlFor="zipSearchInput">Zip Code</label>
<input
{...formMethods.register("zipSearchInput", {
required: true,
minLength: 5,
maxLength: 5
})}
id="zipSearchInput"
name="zipSearchInput"
type="text"
/>
</div>
<button type="submit">Search</button>
</form>
</FormProvider>
</div>
{placeFound.length !== 0 && renderPlaces()}
{errorFound !== "" && <p className="error">{errorFound}</p>}
</div>
);
}
Good Luck