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;