Search input section - KatyaHorton/Udacity-React-practice GitHub Wiki

Search input section

Ways of thinking about forms in React:

  • bypass components' state completely and get your input field directly to the DOM (typical way)
  • React - is made to manage state, so let's pit the form state inside of our component

To build search input section to filter our contact list:

  • connect the input field to whatever the value of a certain property on put state is
  • update the UI based on that form data (which we did bind with the property on our state)

Rule:

If: you want form data to update the UI (besides updating the actual input field itself)

Then: make your form Controlled component

Otherwise: just stick the form data in the DOM to grab it whenever you need it

Creating query state

EUREKA (BINGO/CRACKED IT)!!!

The reason they are called Controlled Components is because the React is controlling the state of the FORM!

The source of truth for the form state lives inside of a component's state, rather than inside of the DOM.

class NameForm extends React.Component {
 state = {  email: '' }
 handleChange = (event) => 
  this.setState({email: event.target.value })
 render () {
  return (
   <form>
    <input type='text' value={this.state.email}>
   </form>
)}}

We can update the state in the input field only if we update the email property of the component state :)

If we want the input field to change we can create a handleChange method that setState() to update the email address:

  • if input field changes
  • we call handleChange() method by passing it to the onChange attribute.

To update the input field we need to update our state (having input state living inside of out component we can update the UI based on that state)

Steps

to create Controlled Component for Search input section

1

Refactor you Stateless Functional component (if you used one) to a class Component.

2

Add query property to our state (string):

state = { 
query: ''
}

3

Wrap all the elements into one div as React is able to return just one elements

<div>
 ...
</div>

4

Create a div with the input field inside, giving it necessary props.

  • we want value always be this.state.query
  • when the input field changes we want to update our query
<input 
 className='search-contacts'
 type='text'
 placeholder='Search contacts'
//we want ```value``` always be ```this.state.query```
 value={this.state.query}
//when the input field changes we want to update our ```query```
 onChange={}
/>

5

Create a method that will update query

  • will take in a new query as an argument
  • update state in based on that new query
updateQuery = (query) => {
 this.setState({ query: query.trim() })
}

6

When ever input field changes it gives us event, which will invoke updateQuery() passing it the specific value of the input field:

  • event is just an event object that React is giving us
  • to get the value of the input field we do event.target.value
  • whenever we type into the input field the onChange() function is invoked
  • that invokes updateQuery() passing it the new string inside of an input field
  • which will then update our state
  • which will then update the specific value of the input field
 onChange={(event) => this.updateQuery(event.target.value)}

To see that we can:

{JSON.stringify(this.state.query)}

Or to display all the state's properties:

{JSON.stringify(this.state)}

7

Install packages to update state to filter contacts:

  • escape-string-regexp
  • sort-by
npm install --save escape-string-regexp sort-by
  • restart application
  • import packages
 import escapeRegExp from 'escape-string-regexp' 
 import sortBy from 'sort-by'

8

By now we have been mapping over all of our contacts, but we should only map over those which match a certain pattern:

Using RegExp (regular expressions):

  • create new variable showingContacts (just contacts which match the specific pattern)
  • if this.state.query truthy (some one has typed smth in our input) - we check which contacts match
  • else (if nothing is typed) - showingContacts will be what ever contacts initially were
render() {
let showingContacts
if (this.state.query) {
... 
} else {
  showingContacts = this.props.conatcs
}
return(
//the rest of the code
)}

9

If this.state.query truthy, we:

  • create new variable match - new instance of RegExp (regular expressions)
  • match - object for matching a specific text in the pattern
  • we pass RegExr the invocation of escapeRegExp, passing it:
  1. our query as a first argument
  2. i as a second argument
let showingContacts
if (this.state.query) {
const match = new RegExp(escapeRegExp(this.state.query), 'i') 
} else {
  showingContacts = this.props.conatcs
}

Walk though: certain characters in RegExp have certain meanings, escapeRegExp(ourQuery) says:

  • 'if there are any special characters in our query - escape them, so we will use the, as a string literal, rather then the special Regexp characters'
  • 'i' also does smth :)

10

Simple example:

  • this will check if 'Tyler' matches this.state.query
  • if it does - returns true
match.text('Tyler')

we say:

  • showingContacts is the result of calling this.props.filter
  • we filter where contacts.name matches our specific RegExp (regular expression) (this.state.query)
  • showingContacts will only be the contacts which match our query
```Javascript
let showingContacts
if (this.state.query) {
 const match = new RegExp(escapeRegExp(this.state.query), 'i') 
 showingContacts = this.props.contacts.filter((contact) => 
 match.test(contact.name))
} else {
  showingContacts = this.props.conatcs
}

11

Instead of mapping over this.prop.contacts - we map over shovingContacts (which is filtered array which match this.state.query)

<ol className='contact-list'>
{showingContacts.map(contact => {
 
//rest of the code

12

Sort contacts by name (sortBy)

 showingContacts.sort(sortBy('name'))

To make code cleaner, you can create variables to store your props and state:

render() {
 const { contacts, onDeleteContact } = this.props
 const { query } = this.state
}

In order not to type each type this.state.query, we now can type query

⚠️ **GitHub.com Fallback** ⚠️