Part one was more about the overview of why I bothered to create my search bar instead of copying other code. This time, I’ll focus on the technical or how and why I implemented it.

Retrieval

Before I even started with the search bar, I needed to ensure the component wouldn’t break if the users’ list took a bit longer to fetch. Slower networks may not respond in a desirable amount of time. After beginning the fetch request for the list, I used a simple ‘if’ statement with a more user-friendly react-bootstrap spinner component, if the fetch was still completing.

Display

After retrieving the current lesson for the user. The search bar needs to render and connect to the component state for later use.

I used a simple form to display the bar, with a bit of react-bootstrap for styling and positioning.

With the state holding the search term, or last name:

While the state updates with every keystroke by the user:

The first iteration of the search bar required the last name to be input and submitted before the search began. As the form is submitted, it invokes the function ‘handleSubmit’:

Once I had completed the search bar functionality, I found it very cumbersome and not as intuitive for the user as I would have liked. Whenever I do create something that requires user interaction, I prefer it to feel effortless and, if possible, familiar. So I added a function that we’ll see later on in another component which rendering invokes. With this, the search would perform with each input change. Thus, giving the user faster and distinct confirmation of the search functioning.

Then the important step. Rendering the results and giving the option to check-in. I felt this was a good point to separate the concerns of rendering the interface and the actual searching. We’ll get back to why this.props.history passes to <SearchResults/>

Search

Before I built the search bar, I rendered another component, <RetrieveCurrentLesson/> , which (you guessed it) renders the current lesson. Understanding how it functions isn’t as important as it’s output. If there were no lessons for the day, it would display ‘No lessons today.’ Otherwise, the current lesson would display with start & end times. The code responsible for this:

I chose this way for a few reasons:

  1. It showed the user there were ‘No Lessons’ instead of blank or undefined.
  2. I thought there would be more confusion if I chose the next lesson to display even if it wasn’t for that day. Even though theoretically, there should be no students if there are no classes. I was building for a less specific and more scaled use.
  3. I could leverage the response of ‘No Lessons’ for the next component.

If there were no lessons for the day, I had to ensure that not only was it stated, but there was also no way to check-in by accident. So, as the component renders, it invokes a simple function to determine whether the check-in button should be enabled or not.

After handling the no lesson errors, the search functionality comes next. When the component renders, it invokes this.filterUsers(this.props) and maps over the output to display the user that matches the search term. The function itself filters the user list and compares the last name to the search term.

With the selected user now being displayed with first name, last name, and rank. The button to check-in and attach the user displays with the following code <Button variant="success" disabled={!isEnabled} onClick={() => this.attachUser(user)}> Check-In </Button> :

Association

When the button is enabled and clicked, it invokes the attachUser function and passes the user as an argument. attachUser has a few responsibilities.

First, it grabs the currentLesson from the redux store or props. It can then add the user to the list of users associated with the lesson and invoke the associateUser action, made available through redux export default connect(state => ({ currentLesson: state.currentLesson }), {associateUser})(SearchResults) .

As you can see, associateUser is a pretty standard fetch asynchronous request. It updates the provided lesson and expects the updated lesson back as the payload. I also added the history prop we previously passed down, which allows me to use this: window.location.reload(false) . It reloads the page, leaving it ready for the next user to check in with a cleared search bar. The 'false' argument tells window.location.reload to reload from cache if possible. Reloading with cache is faster and won’t affect the search bar functionality.

Conclusion

I enjoyed going through each step and having to research every option to decide what was best for my situation.

In the future, I’d like to experiment with large data sets to see if the constant rendering of components due to user input change, makes a performance difference. With the small data set I used and the overall better user experience, I preferred this way.

If you have any questions or comments on how I can improve this, let me know! I’m a junior developer, I’m always learning and improving.

Code Repo

If you'd like to check out more of the code or suggest improvements. Here's the repo:

Attribution

Cover Photo by Andrew Ridley on Unsplash

This post is also available on DEV.