Add TypeScript to a component props that also has an change event handler:
import { ChangeEventHandler } from "react";
import "./search-box.styles.css";
type SearchBoxProps = {
className: string;
placeholder?: string;
onChangeHandler: ChangeEventHandler<HTMLInputElement>;
};
const SearchBox = ({
className,
placeholder,
onChangeHandler
}: SearchBoxProps) => (
<input
className={`search-box ${className}`}
type="search"
placeholder={placeholder}
onChange={onChangeHandler}
/>
);
export default SearchBox;
You can pass on an array (Monster
) from data fetching to setting the state on monsters
and filteredMonsters
. You’ll notice filteredMonsters
inherits the array from monsters
and doesn’t need to be defined again.
import { useState, useEffect, ChangeEvent } from 'react';
import CardList from './components/card-list/card-list.component.tsx';
import SearchBox from './components/search-box/search-box.component.tsx';
import { getData } from './utils/data.utils.ts';
import './App.css';
export type Monster = {
id: string,
name: string,
email: string
}
const App = () => {
const [searchField, setSearchField] = useState('');
const [monsters, setMonsters] = useState<Monster[]>([]);
const [filteredMonsters, setFilterMonsters] = useState(monsters);
useEffect(() => {
const fetchUsers = async () => {
const users = await getData<Monster[]>('https://jsonplaceholder.typicode.com/users');
setMonsters(users);
}
fetchUsers();
}, []);
useEffect(() => {
const newFilteredMonsters = monsters.filter((monster) => {
return monster.name.toLocaleLowerCase().includes(searchField);
});
setFilterMonsters(newFilteredMonsters);
}, [monsters, searchField]);
const onSearchChange = (event: ChangeEvent<HTMLInputElement>): void => {
const searchFieldString = event.target.value.toLocaleLowerCase();
setSearchField(searchFieldString);
};
return (
<div className='App'>
<h1 className='app-title'>Monsters Rolodex</h1>
<SearchBox
className='monsters-search-box'
onChangeHandler={onSearchChange}
placeholder='search monsters'
/>
<CardList monsters={filteredMonsters} />
</div>
);
};
export default App;
Finally you can import the Monster
array from a parent component to pass along as the props like this:
import { Monster } from '../../App.tsx';
import Card from '../card/card.component.tsx';
import './card-list.styles.css';
type CardListProps = {
monsters: Monster[]
}
const CardList = ({ monsters }: CardListProps) => (
<div className='card-list'>
{monsters.map((monster) => {
return <Card key={monster.id} monster={monster} />;
})}
</div>
);
export default CardList;