DEV Community

Cover image for Let's build a search bar in React!

Let's build a search bar in React!

Tim Smith on September 11, 2018

The original version of this article can be found here. I know, I know...another task app... Hear me out though! We are going to build a task app...
Collapse
 
zrbecker profile image
Zachary Becker

Thanks for the article.

You addItem/removeItem has a fairly unlikely race condition in it.

You are reading the list from the state, modifying it, then using this.setState. However, this.setState does not update the state immediately.

In theory, addItem could get called twice in quick succession, and you would lose one of the items added. For example with this possible ordering of events:

  • Initial List ["a", "b", "c"]
  • addItem Called with "d", modified list ["a", "b", "c", "d"], setState called
  • addItem called with "e", modified list ["a", "b", "c", "e"], setState called
  • State is updated with ["a", "b", "c", "d"]
  • State is updated with ["a", "b", "c", "e"]

Just something to keep in mind.

Collapse
 
iam_timsmith profile image
Tim Smith

Interesting. How would you suggest preventing that issue in a project like this?

Collapse
 
zrbecker profile image
Zachary Becker • Edited

Use call back format for setState.

this.setState(state => {
  const list = state.list;
  /* modify list */;
  return {
    list: modifiedList
  };
});
Enter fullscreen mode Exit fullscreen mode
Collapse
 
davidasync profile image
David Async • Edited

Great tutorial, but why not use facebook cra instead ?

Collapse
 
dance2die profile image
Sung M. Kim

If cra is your choice, you can try c-r-a-p 💩-create-react-app-parcel 😃

Collapse
 
iam_timsmith profile image
Tim Smith

I have not heard of this. It looks cool though. Thanks for the link!

Collapse
 
iam_timsmith profile image
Tim Smith

It’s really personal preference, but to be honest I haven’t used create-react-app in a while and forgot it existed.

Collapse
 
migueloop profile image
Miguel Ruiz

At the end It's better to make it your own way. create-react-app is for fast dev or examples but not for real projects.

Thread Thread
 
jason_espin profile image
Jason Espin

That's not necessarily true. I know plenty of enterprit level projects that use React that were created with CRA. As long as you configure and secure it, it's the best solution for making a start on a React project.

Thread Thread
 
migueloop profile image
Miguel Ruiz

I recommend you to read this article:

medium.com/@francesco.agnoletto/i-...

Thread Thread
 
jason_espin profile image
Jason Espin

I couldn't disagree with this more. In a majority of cases you don't need any additional configuration.

Collapse
 
machy44 profile image
machy44 • Edited

Nice Article.

When I use getDerivedStateFromProps() in same way you use componentWillReceiveProps() in List component searching doesn't work.

static getDerivedStateFromProps(nextProps) {
return {
filtered: nextProps.items
};
}

I didn't know that getDerivedStateFromProps is called every time we setState(). Link for lifecycles projects.wojtekmaj.pl/react-lifecy....

I wanted to share this thought with you cause I didn't give enough attention about differences between componentWillReceiveProps and getDerivedStateFromProps and IMHO this is kind of important.

Collapse
 
iam_timsmith profile image
Tim Smith

This is awesome! Thanks for the link!

Collapse
 
machy44 profile image
machy44

Np. Thank you for the article

Collapse
 
nemethricsi profile image
Richard • Edited

Hi there,

Really liked your tutorial Tim! <3 I thought I try all of that with functional components and this is what I got (feel free to correct me - I'm kinda rookie in webdev). Seems working though!

Minor changes I made:

  • used functional components instead of class components. Therefore used React.useState() for storing variables in the state.

  • input element for adding new todo is a controlled component and handled also in the state. Found this approach more "react-ish".

  • for deleting a todo I also used filter() method - seems more handy for me.

  • some naming changes

App.js

// App.js

import React, { useState, Fragment } from "react";
import List from "./List";

const App = () => {
  const [userInput, setUserInput] = useState("");
  const [list, setList] = useState([
    "walk the dog",
    "buy the milk",
    "learn some code"
  ]);

  // userinput is controlled by the App component
  const handleChange = e => {
    setUserInput(e.target.value);
  };

  const addItem = e => {
    if (userInput !== "") {
      setList([...list, userInput]);
      setUserInput("");
    }
  };

  const removeItem = item => {
    const updatedList = list.filter(listItem => listItem !== item);
    setList(updatedList);
  };

  return (
    <Fragment>
      <List list={list} removeItem={removeItem} />
      <hr />
      <form>
        <input
          placeholder="Something that needs to be done..."
          value={userInput}
          onChange={handleChange}
        />
        <button type="button" onClick={addItem}>
          {'Add Item'}
        </button>
      </form>
    </Fragment>
  );
}

export default App;

List component:

// List.js

import React, { useState, useEffect, Fragment } from "react";

const List = ({ list, removeItem }) => {
  const [filtered, setFiltered] = useState([]);

  useEffect(() => {
    setFiltered(list);
  }, [list]);

  const handleChange = e => {
    let currentList = [];
    let newList = [];

    if (e.target.value !== "") {
      currentList = list;
      newList = currentList.filter(item => {
        const lc = item.toLowerCase();
        const filter = e.target.value.toLowerCase();
        return lc.includes(filter);
      });
    } else {
      newList = list;
    }
    setFiltered(newList);
  };

  return (
    <Fragment>
      <input 
        type="text" 
        placeholder="Search..." 
        onChange={handleChange} 
      />
      <ul>
        {filtered.map((todo, i) => (
          <li key={`${todo}-${i}`}>
            {todo} &nbsp;
            <span onClick={() => removeItem(todo)}>x</span>
          </li>
        ))}
      </ul>
    </Fragment>
  );
};

export default List;

default create-react-app index.js...

// index.js

import React from "react";
import ReactDOM from "react-dom";

import App from "./App";

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  rootElement
);
Collapse
 
skillitzimberg profile image
Scott Bergler

"Fair warning: This part may get a bit abstract, so do your best to stick with me. If I don't explain well enough or you're struggling with it, leave a comment and I'll try to help you get it." ~ T. Smith

I love the generous spirit and the acknowledgement that sometimes what we think we're say/writing is not what is heard/understood.

Collapse
 
moopet profile image
Ben Sinclair

There's a typo: mkdir search-tasks && $_ should be mkdir search-tasks && cd $_

Collapse
 
iam_timsmith profile image
Tim Smith

Fixed. Thank you!

Collapse
 
victortolbert profile image
Victor Tolbert

Thanks for the article.

FYI, I don't see the instructions to modify the package.json to include the start script.

Collapse
 
iam_timsmith profile image
Tim Smith

Thanks! I have added the piece about scripts in the package.json file.

Collapse
 
sagar profile image
Sagar

Hi Tim,

I found typo error at Next we need to install the necessary packages to our package. => Next we need to install the necessary packages to our project

Collapse
 
iam_timsmith profile image
Tim Smith

Corrected. Good catch. It sounded like I was trying to be xhibit or something.

Collapse
 
maynardhartman profile image
Maynard J. Hartman, Jr.

Great Article Thanks...

Collapse
 
iam_timsmith profile image
Tim Smith

No problem. I’m glad it was helpful!

Collapse
 
anascann profile image
Anas Khan

Hey! nice article. but how do we implement search via using two keywords. like i have rows of some information. i want to search using keywords age and gender. any idea?

Collapse
 
anproghub profile image
Ankush Chauhan

how to add not found text when the user didn't find any related results?

view here - loom.com/share/59eed867b4594ace89e...

Collapse
 
dsavai profile image
Dennis savai

If you get an error when importing like --> import 'bulma/bulma' use --> import 'bulma/css/bulma.css'