Hey! I'm on a mission to make 100 React.js projects ending March 31st. Please follow my dev.to profile or my twitter for updates and feel free to reach out if you have questions. Thanks for your support!
Link to the deployed project: Link
Link to the repo: github
Today I wanted to create an autocomplete component in React because I haven't implemented search in React before much less autocomplete. I'm actually curious how other people implement this from scratch because with the Star Wars API it's fairly easy. They have their own search feature that returns an array of JSON results and the number of Star Wars characters any search is going to return is necessarily small. What if your database has 100,000 possible results? I suppose you could put a numeric limit on the results in most databases.
For the basic search component I adapted this Dev.to blog post into a functional component. Rather than use their API, I decided to use a Star Wars character search API that is open and doesn't require a signup that exposes my email.
The structure of the website is simple. It uses an App
component and a Search
component, where the important logic happens. It uses three pieces of state- query
, searchResults
and selectedCharacter
which are all set to empty at initialization:
const [query,setQuery] = useState('');
const [searchResults,setSearchResults] = useState([]);
const [selectedCharacter,setSelectedCharacter] = useState(null);
In the return statement we create a form with a text input for the search feature:
return (
<form className='search-form-container'>
<input
placeholder='Search for...'
onChange={handleInputChange}
value={query}
/>
</form>
)
As the user searches we initiate the API call to the Star Wars API using their search URL query:
const searchURL = 'https://swapi.dev/api/people/?search=';
const getInfo = () => {
console.log('Getting info from API...')
fetch(searchURL+query)
.then(res => res.json())
.then(data => setSearchResults(data.results))
.catch(e => {
console.log({error: e});
});
}
const handleInputChange = (e) => {
setQuery(e.target.value)
if (query && query.length > 0) {
getInfo();
}
}
If results are returned from the API, we populate a ul
element beneath the search box with results. I usually use the standard map method and create a key
prop for the returned JSX children but I wanted to implement this a new way- with the React.Children.toArray()
method. This way, you don't have to create your own key prop.
const results = React.Children.toArray(
searchResults.map((item,idx) => (
<li className='result-item' id={idx} onClick={handleQueryResultClick}>{item.name}</li>
))
)
That looks like the following:
If the user selects one of these li
elements, the index of that element from the original array of results stored in searchResults
will match up with the id of the li
element.
const handleQueryResultClick = (e) => {
const searchResultId = e.target.id;
setSelectedCharacter(searchResults[searchResultId]);
setQuery([]);
}
We then populate select data from that character's search into a div below the search box and clear the query state to remove the ul
element of search results. I did this with a ternary.
<div>
{selectedCharacter ? (
<div className='character-display-container'>
<p><span className='character-info-title'>name:</span> {selectedCharacter.name}</p>
<p><span className='character-info-title'>height:</span> {selectedCharacter.height}</p>
<p><span className='character-info-title'>mass:</span> {selectedCharacter.mass}</p>
</div>
) : (
<p className='no-results-prompt'>There are no results. Try typing something into the search bar above.</p>
)}
</div>
That's it! It was easier than I expected, largely because the API is so easy to use. I highly encourage you to try it.
Top comments (15)
This is pretty cool! 👍
I'd recommend checking out datalist html element for displaying the autocomplete results as it helps with accessibility and ordering results based on the input!
Thanks a bunch Jordan! I’ll definitely check out the data list html component and try to use it in a project.
Quality for project also matter, not required to build 100 project
Thanks Shubham. It’s just a motivator for me- sort of a step up from #100daysofcode.
Do you think the project lacks quality? I like doing this exercise because it allows me to work on small challenges versus building whole apps.
It is awesome James!
This will help many people.
I agree with your paradigm of projects instead of code. I also agree with these simple projects because large systems are made up of a combination of them
Thanks Orim! It's really hard... I'm not going to lie. Sometimes I can't do a project in a day and I have to do an extra one on the weekend when I have time. But overall I think the effort it's a good strategy.
Let me know if you do a #100daysofreact or #100daysofcode! I will rep you on dev.to and on Twitter :)
I don't feel you MUST do a project each day. By what you've said, it's already leading to burnout. You are a human and you should take care of yourself. You are more useful to the world when you're healthy.
That being said, you can skip some days. It's #100DaysOfProjects, not #100ConsecutiveDaysOfProjects.
I'll let you know definitely if I ever start one.
yes you are right, but for app hosting feature can be more in deployment
Thanks Orim. I think you're right- and please do :)
Thanks james for understanding my good intend and positive reply. i saw your task, you are doing good but i want if you host app that time try to add more features so this will attractive
so nice and straight forward explaination.
Thanks Ratul!
Excellent I would try to follow all of your #100DaysOfCode projects but with Vue. Keep up the good work bro. Take care :)
I can't wait to learn Vue! It may just be next if I can learn React Native within this 100 days challenge :)
Thanks Riguidix!
I am new to react. Thanx for posting the code, I can learn from it.