Home > Back-end >  searchfield with redux with functional components
searchfield with redux with functional components

Time:12-13

I have a react application and a search functionality. But now I try to implement redux with the application. So if I load the application no errors. But if I just type something in the searchbox I get this error:

TypeError: searchfield.toLowerCase is not a function

//const { robots, searchfield } = this.state;
  44 | //const {searchField, onSearchChange} = props;
  45 | const filteredRobots = robots.filter(robot => {
> 46 |   return robot.name.toLowerCase().includes(searchfield.toLowerCase());
     | ^  47 | });
  48 | return !robots.length ?
  49 |   <h1>Loading</h1> :

So this is app.js:


const mapStateToProps = state => {
  return {
    searchField: state.searchfield
  }
};

const mapDispatchToProps = dispatch => {
  return {
    onSearchChange: (event) => dispatch(setSearchField(event.target.value))
  }
}

function App(props) {
  

  const [robots, robotState] = useState([]);
  const [searchfield, stateSearchField] = useState('');


  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users')
      .then(response => response.json())
      .then(users => { robotState(users) });   
  }, []);


  const filteredRobots = robots.filter(robot => {
    return robot.name.toLowerCase().includes(searchfield.toLowerCase());
  });
  return !robots.length ?
    <h1>Loading</h1> :
    (
      <div className='tc'>
        <h1 className='f1'>RoboFriends</h1>
        <SearchBox searchChange={stateSearchField} />
        <Scroll>
          <CardList robots={filteredRobots} />
        </Scroll>
      </div>
    );

}

export default connect(mapStateToProps, mapDispatchToProps)(App);

reducer.js:

import { CHANGE_SEARCH_FIELD } from './constants.js';


const initialState = {
    searchField: ''
}

export const searchRobots = (state = initialState, action = {}) => {
    switch (action.type) {
        case CHANGE_SEARCH_FIELD:
            return Object.assign({}, state, { searchField: action.payload });
        default:
            return state;
    }
}

actions.js

import {CHANGE_SEARCH_FIELD} from './constants'

export const setSearchField = (text)=> ({
                type: CHANGE_SEARCH_FIELD,
                payload: text

});

searchbox.js

import React from 'react';

const SearchBox = ({ searchfield, searchChange }) => {
  return (
    <div className='pa2'>
      <input
        className='pa3 ba b--green bg-lightest-blue'
        type='search'
        placeholder='search robots'
        onChange={searchChange}
      />
    </div>
  );
}

export default SearchBox;

my question: what I have to change?

Thank you

CodePudding user response:

The stateSearchField is the function responsible to record/updating the value of searchfield variable of the useState hook. The cause of this issue is that you aren't updating the values properly as and when the input is given/updated. The SearchBox component's searchChange props point to stateSearchField which is further triggered when the input value is changed. But the problem here is that, the input value is not passed when updating the state, hence it is setting the searchfield value to undefined, and in the filter function you are trying to invoke the method toLowerCase() on searchfield which is undefined. The fix is pretty simple, just pass the input value whenever the input is changed. This can be done in the SearchBox component.

import React from 'react';

const SearchBox = ({ searchfield, searchChange }) => {
  return (
    <div className='pa2'>
      <input
        className='pa3 ba b--green bg-lightest-blue'
        type='search'
        placeholder='search robots'
        onChange={e=>searchChange(e.target.value)} //accept the event argument and pass the extracted value from the input to searchChange prop function.
      />
    </div>
  );
}

export default SearchBox;

Or use a handler function to accomplish the same,

import React from 'react';

const SearchBox = ({ searchfield, searchChange }) => {
  function updateInput(e){
    searchChange(e.target.value)
  }
  return (
    <div className='pa2'>
      <input
        className='pa3 ba b--green bg-lightest-blue'
        type='search'
        placeholder='search robots'
        onChange={updateInput}
      />
    </div>
  );
}

export default SearchBox;
  • Related