findDOMNode() For Select Element Not Working - javascript

I have a form with select element. The values for options for select element comes from an API. So, I have to dynamically create the options. But, I am unable to get the select element from DOM.
Following is the code that have tried. I tried to access select ID element with findDOMNode. None of this is getting the element.
What do I need to do to get the element selected?
componentDidMount() {
companyUserNames()
.then(result => {
const companyUsername = result;
console.log(result);
//output ==> [ { userName: "ABC",fullName: "ABC XYZ"}, {userName:
// "DEF",fullName: "DEF QRW"}]
companyUsername.forEach(role => {
console.log(role);
const roledynamic1 = document.getElementById("name1");
console.log(roledynamic3);
//output = null
const roledynamic2 = this.refs.name1
console.log(roledynamic3);
//output = undefiend
const roledynamic3 = ReactDOM.findDOMNode(this.refs.name1)
console.log(roledynamic3);
//output = null
const newchild1 = document.createElement("option");
newchild1.value = role.userName;
newchild1.text = role.fullName;
roledynamic3.add(newchild1);
});
})
.catch(error => {
console.log(error);
});
}
render(){
return(
<form>
//some input field
<div className='select'>
<select
name='userName'
id='name1'
ref="name1"
className='input common-input-style'
maxLength='255'
value={this.state.userName.value}
onChange={this.handleInputChange}
>
<option>Name</option>
</select>
</div>
//some input field
<form/>
)
}

findDOMNode accepts a component as an argument, not a ref.
Try using the ref directly it should hold the DOM node.
Note that findDOMNode is a deprecated API and should be avoided.
Also, as Amin Paks mentioned you should consider switching to the current style of using refs with createRef

Why do you need to access DOM node when you can easily work with state in react.
Below is the working code with codesandbox link:-
import React from "react";
import ReactDOM from "react-dom";
class App extends React.Component {
state = {
names: []
};
companyUserNames = () => {
return new Promise(resolve => {
return resolve([
{ userName: "ABC", fullName: "ABC XYZ" },
{ userName: "DEF", fullName: "DEF QRW" }
]);
});
};
componentDidMount() {
this.companyUserNames()
.then(result => {
this.setState({
names: result
});
})
.catch(error => {
console.log(error);
});
}
render() {
const { names } = this.state;
let namesList =
names.length > 0 &&
names.map((item, i) => {
return (
<option key={i} value={item.userName}>
{item.fullName}
</option>
);
});
return (
<form>
<div className="select">
<select className="input common-input-style" maxLength="255">
{namesList}
</select>
</div>
</form>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Related

TypeError: Cannot read property 'value' of undefined in React JS

I am fairly new to react JS and I've implemented 2 dropdown boxes whose options are displayed by hitting an API. I want to obtain the selected value but I am getting the following error:
TypeError: Cannot read property 'value' of undefined.
As of now I just tried to obtain the value from one dropdown.
This is my code,
import React from 'react';
import Select from 'react-select';
import './Search.css';
class SearchForm extends React.Component {
constructor(props){
super(props);
this.state={
filtered :[],
values1 :[],
values2 :[],
selectedCategory:''
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
try{
this.setState({selectedCategory: event.target.value});
} catch (err) {
console.error('err', err);}}
componentDidMount() {
this.fetchData1()
this.fetchData2()
}
fetchData1 = async () => {
await fetch('/category/all')
.then(res => res.json())
.then(res =>
this.setState({
values1: res,
}),
)
.catch(error => console.log(error))
}
fetchData2 = async () => {
await fetch('/loc/all')
.then(res => res.json())
.then(res =>
this.setState({
values2: res,
}),
)
.catch(error => console.log(error))
}
async handleSubmit(event){
event.preventDefault();
try{
const url ='/jobs/all/'
const Response = await fetch((url),{
method: `GET`,
mode: 'cors',
headers: {
'Accept': 'application/json'
}});
const filtered = [];
const res = await Response.json();
const Location = this.menu2.value
const Category = this.menu1.value
console.log(Location)
console.log(Category)
Object.keys( res ).forEach( function( key ) {
if( res[key].location === Location && res[key].category === Category ) {
filtered[key] = res[key];}
});
this.setState({filtered})
console.log(this.state.filtered)
}
catch (err) {
console.error('err', err);}
};
render() {
let option1 = []
if (this.state.values1) {
this.state.values1.forEach(eachCategory => {
let Category = {}
Category.value = eachCategory.id
Category.label = eachCategory.category
option1.push(Category)
})
}
console.log(option1)
let option2 = []
if (this.state.values2) {
this.state.values2.forEach(eachLocation => {
let Location = {}
Location.value = eachLocation.id
Location.label = eachLocation.location
option2.push(Location)
})
}
console.log(option2)
return (
<div>
<form action="/search" onSubmit={this.handleSubmit.bind(this)}>
<Select options={option1} value={this.state.selectedCategory} placeholder='Category' onChange={this.handleChange}>
</Select>
<Select options={option2} placeholder='Location'/>
<button>Find</button>
</form>
{this.state.filtered.map((data)=>{
// return <div>{data.location}</div> // you can render here list items
return (
<div className="flex-container">
<div key={data.id}>
<div>Job Title: {data.category}</div>
<div>Location: {data.location}</div>
<div>Position: {data.position}</div>
<div>Duration: {data.duration}</div>
<div>Skills Required: {data.skills_req}</div>
<div>Apply By: {data.apply_by}</div>
<div>Starting Date: {data.starting_date}</div>
<div>Stipend: {data.stipend}</div>
<div>About Work: {data.about_work}</div>
<div>Perks: {data.perks}</div>
</div>
</div>)
})}
</div>
);
}
}
export default SearchForm;
Please point out where am I wrong.
Well, according to the react-select documentation you're handling onChange in a wrong way. It should just be like this.
handleChange = selectedOption => {
this.setState({ selectedOption });
console.log(`Option selected:`, selectedOption);
};
https://www.npmjs.com/package/react-select
So in your case, you just have to change this.setState({selectedCategory: event.target.value}); to this.setState({selectedCategory: event}); :
handleChange(event) { //give it a proper name, say selectedValue instead ofevent'
try{
this.setState({selectedCategory: event}); //no need of event.target.vaue; in fact that will be undefined
} catch (err) {
console.error('err', err);}}
Please note that this Select is different from normal select where you get the value using e.target.value in the handleChange method. The Select comes in with react-select package and hence you need to follow the usage accordingly.
You didn't send event to handleChange method.
Try:
onChange={e => this.handleChange(e)}

Remove Item on click in React [duplicate]

This question already has answers here:
Removing element from array in component state
(11 answers)
Closed 3 years ago.
I have a names list which contains 3 names. On clicking any 1, you can edit and save. That value updates to the list. Now I can add how many ever names I want but I am not able to delete/remove any.
This is how it looks in the beginning
On clicking a name (the whole container) it looks like this
I am able to add the new name back to the div like this
And I can add as many as I want, like this like this
Now I want to be able to click on the cross icon and remove the whole element I want. It should go be gone from the page. The other elements should take its place from top to bottom. Remove/delete functionality should be on input and the div with names in it.
Names Component (Names are extracted from this to the one below)
import Sukhdev from '../../../src/components/sukhdev';
import React from 'react';
export default { title: 'Sukhdev' };
const names = [{
firstName: "Mahatma",
lastName: "Gandhi"
}, {
firstName: "Shivaji",
lastName: "Maharaj"
}, {
firstName: "Bhagat",
lastName: "Singh"
},
]
export const sukhdev = () => {
return(
<Sukhdev names={names}/>
)
}
Parent Component
import React, { Component } from 'react';
import FirstName from './firstName';
import LastName from './lastName';
import TextArea from './textArea'
import styles from './styles';
export default class Sukhdev extends Component {
constructor(props) {
super(props);
const {names} = this.props;
const updatedNames = names.map((name) => ({...name, ...{isEditable: false}}));
this.state = {
userNames: updatedNames
}
}
inputNamesHandler = (namesIndex) => {
const updatedUserNameDetails = [...this.state.userNames];
updatedUserNameDetails[namesIndex].isEditable = true;
this.setState({userNames: updatedUserNameDetails})
}
saveButton = (inputValue, index) => {
const {userNames} = this.state;
const newNames = [...userNames];
newNames[index] = {...newNames[index], isEditable: false, firstName: inputValue, lastName: ''};
this.setState({
userNames: newNames
})
}
addChild = () => {
const createInputs = [...this.state.userNames];
createInputs.push({firstName: '', lastName: '', isEditable: true});
this.setState({
userNames: createInputs
})
}
------> // This is where the changes need to be made
deleteRow = (index) => {
const postDelete = [...this.state.userNames];
postDelete.slice(index, 1);
this.setState({
userNames: postDelete
})
}
render() {
return <div>
<h1>Names</h1>
<button onClick={this.addChild} style={styles.button}>Add New</button>
<div>
{this.state.userNames.map((nameDetails, index) => {
if(nameDetails.isEditable) {
return <div>
<TextArea clicked={(name) => this.saveButton(name, index)}/>
</div>;
} else {
return <div style={styles.namesContainer}>
<div onClick={() => this.inputNamesHandler(index)} style={styles.innerContainerComponent}>
<div style={styles.firstMargin}><FirstName firstName={nameDetails.firstName}></FirstName></div>
<div><LastName lastName={nameDetails.lastName}></LastName></div>
</div>
<img src={require('../../images/cancel.png')} style={styles.crossBtn} onClick={() => this.deleteRow(index)} />
</div>
}
})}
</div>
</div>
}
}
Textarea/Input Component
import React, { Component } from "react";
import styles from './styles'
export default class TextArea extends Component {
constructor(props) {
super(props);
this.state = {value:''}
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
return (
<div>
<div style={styles.inputContainer}>
<input type="text" style={styles.textField} value={this.state.value} onChange={this.handleChange}></input>
<button type="submit" style={styles.saveButton} onClick={() => this.props.clicked(this.state.value)}>Save</button>
<img src={require('../../images/cancel.png')} style={styles.crossBtn} />
</div>
</div>
)
}
}
First name and last name are imported by parent component in this way
import React, {Component} from 'react';
export default class FirstName extends Component {
render() {
return <div>{this.props.firstName}</div>
}
}
Last name is also like the code given above.
slice does not modify the original array, but returns a new array with the modified values. You need to assign it to a new variable or use a different method of deleting the value.
let newArray = postDelete.slice(index, index + 1);
this.setState({
userNames: newArray
})
In fact, since slice does not mutate the array, you could simplify to this:
this.setState((prevState) => ({
userNames: prevState.userNames.slice(index, index + 1)
)})
However, to accomplish this specific task, you should use a different method like filter
this.setState((prevState) => ({
userNames: prevState.userNames.filter((v,i) => i != index)
)})
This will iterate through the array and filter out all that don't meet the condition. The first argument is the current value and the second is the index. So we only want to keep the values that do not match our index variable.
class App extends React.Component {
state = {
users: [
{
firstName: "Lionel",
lastName: "Messi"
},
{
firstName: "Cristiano",
lastName: "Ronaldo"
},
{
firstName: "Neymar",
lastName: "Jr."
},
{
firstName: "Zlatan",
lastName: "Ibrahimovic"
},
{
firstName: "Ricardo",
lastName: "Kaka"
}
]
};
updateUsers = (updatedUser, index) => {
var users = [...this.state.users];
users[index] = updatedUser;
this.setState({
users
});
};
deleteUser = index => {
var users = [...this.state.users];
users.splice(index, 1);
this.setState({
users
});
};
render() {
return (
<div>
{this.state.users.map((user, index) => {
return (
<PlayerBox
user={user}
key={Math.random()}
index={index}
updateUsers={this.updateUsers}
deleteUser={this.deleteUser}
/>
);
})}
<h1> {JSON.stringify(this.state.users)} </h1>
</div>
);
}
}
class PlayerBox extends React.Component {
state = {
editMode: false,
firstName: "",
lastName: ""
};
componentDidMount() {
const { firstName, lastName } = this.props.user;
this.setState({
firstName,
lastName
});
}
updateParent = () => {
const { index, updateUsers } = this.props;
updateUsers(
{
firstName: this.state.firstName,
lastName: this.state.lastName
},
index
);
this.setState({
editMode: false
});
};
deleteUser = () => {
const { deleteUser, index } = this.props;
this.setState({
editMode: false
});
deleteUser(index);
};
render() {
const { firstName, lastName } = this.props.user;
return this.state.editMode ? (
<div>
<div>
<input
type="text"
value={this.state.firstName}
onChange={e =>
this.setState({
firstName: e.target.value
})
}
/>
<input
type="text"
value={this.state.lastName}
onChange={e =>
this.setState({
lastName: e.target.value
})
}
/>
<button type="submit" onClick={this.updateParent}>
Save
</button>
<button onClick={this.deleteUser}> Delete </button>
</div>
</div>
) : (
<div
onClick={() =>
this.setState({
editMode: true
})
}
>
{firstName} {lastName}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

How to parse result from backend to dropdown react axios?

I'm learning React, I made a page with Form.
This Form should get data from back-end via axios.
I need help because whatever I do, array doesn't display in the select options.
Example of data:
[{"country": "Germany" "code": 112 }]
import React, { Component } from 'react';
import { Row, Col, Button, Form } from 'react-bootstrap';
import axios from 'axios';
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
country: []
};
}
componentDidMount() {
axios
.get('URL')
.then((response) => {
console.log(response);
this.setState({
country: response
});
})
.catch((error) => console.log(error.response));
}
handleChangeCountry = (event) => {
this.setState({ country: event.target.value });
};
inputCountryHandler = (event) => {
this.setState({
input: {
country: event.target.value
}
});
};
render() {
// const { country} = this.state;
return (
<Form className="calculator-table">
<Form.Group controlId="first-row" className="Focus-line">
<Form.Label>Country</Form.Label>
<Form.Control
as="select"
className="User-Input"
placeholder=""
value={this.state.country}
onChange={this.handleChangeCountry}
id="country"
option={this.country}
/>
</Form.Group>
);
}
}
export default Form;
I want the array data to be displayed in drop down select.
Thanks for any answer
You should first parse the JSON response from the API.
componentDidMount() {
axios
.get('URL')
.then((response) => {
console.log(response);
this.setState({
country: JSON.parse(response) //parse the response
});
})
.catch((error) => console.log(error.response));
}
As per the docs, Form.Control don't accept option as props.
You must iterate your country array to get the options.
<Form.Control
as = "select"
className = "User-Input"
placeholder = ""
value = { this.state.selectedCountry }
onChange = { this.handleChangeCountry }
id = "country" //Remove this id, otherwise you will get the warning
>
{
this.state.country && this.state.country.length > 0 && this.state.country.map(countryItem => <option key={countryItem.country}>{countryItem.country}</option>)
}
</Form.Control>
You should have a separate state variable to store the selected value,
constructor(props) {
super(props);
this.state = {
country: [],
selectedCountry: '' //add this to store selected country value
};
}
And your handleChangeCountry function should be,
handleChangeCountry = (event) => {
this.setState({ selectedCountry: event.target.value });
};
Note: axios return response in JSON format, but the actual data is in response.data, so you should set your state as,
this.setState({
country: response.data
});
When you specify id = 'country', you will get warning,
Warning: controlId is ignored on <FormControl> when id is specified.
You should remove the id = 'country'.
I believe the issue is that the Form.Control component as select expects options as children components. So you would need to map over the response array like so:
<Form.Control as="select">
{this.state.country.map(response => {
<option>{response.country}</option>
})}
</Form.Control>
According to docs you must use array of option
<Form.Control
as="select"
className="User-Input"
placeholder=""
value={this.state.country}
onChange={this.handleChangeCountry}
id="country">
{
this.state.country.map((c, i) => <option value={c.code} key={i}>{c.country}</option>)
}
</Form.Control>
Also, you have to use 2 state variables, example
this.state = {
selectedCountries: [], // from select control
country: [] // from backend
}
And populate select value from this.state.selectedCountries

How to list all suggestions and filtered suggestions based on user input using reactjs?

i want to show all available usernames when user types # in input field and filtered usernames when user enters anything after # character.
I have implemented like below,
class UserMention extends React.purecomponent {
constructor(props) {
super(props);
this.state = {
text: '',
user_mention: false,
};
this.user='';
}
user_list = [
{name: 'John smith'},
{name: 'Jenna surname2'},
{name: 'Tuija rajala'},
];
get_user = s => s.includes('#') && s.substr(s.lastIndexOf('#') +
1).split(' ')[0];
handle_input_change = (event) => {
let user_mention;
this.user = this.get_user(event.target.value);
if (event.target.value.endsWith('#')) {
user_mention = true;
} else {
user_mention = false;
}
this.setState({
user_mention: user_mention,
[event.target.name]: event.target.value,
});
};
get_text_with_user_mention = (text, selected_user) => {
let user_name = selected_user;
let text_without_user_mention;
text_without_user_mention = text.slice(0,
text.lastIndexOf('#'));
return text_without_user_mention + user_name;
};
handle_select_value = (selected_user) => {
let text;
text = this.get_text_with_user_mention(this.state.text,
selected_user);
this.setState({
text: text,
user_mention: false,
});
this.user = false;
};
render = () => {
let suggested_values = [];
if (this.state.user_mention) {
suggested_values = this.user_list
.map((o) => { return {user_name: o.user_name};});
}
if (this.user) {
suggested_values = this.user_list
.filter(user => user.user_name.indexOf(this.user) !==
-1)
.map((o) => {return {user_name: o.user_name};});
}
return (
<input
required
name="text"
value={this.state.text}
onChange={this.handle_input_change}
type="text"/>
{this.state.user_mention &&
<SelectInput
on_change={this.handle_select_value}
values={suggested_values}/>}
{this.user &&
<SelectInput
on_change={this.handle_select_value}
values={suggested_values}/>}
);
};
}
As you see from above code, i am modifying suggested_values based on this.user and this.state.user_mention state. Can someone help me refactor or modify this a bit more nicer. thanks.
This is another approach using React hooks, instead of classes. If you've never worked with hooks, give it a try. You will enjoy it. It's much simpler in my opinion.
I also added a username property. It's much better if you work with a string that doesn't allow spaces when you're tagging someone. You can also display the full name with spaces along with the username, if you wish.
Ex:
John Smith (#johnsmith)
function App() {
const inputRef = React.useRef(null);
const [inputValue, setInputValue] = React.useState('');
const [userList,setUserList] = React.useState([
{name: 'John smith', username:'johnsmith'},
{name: 'Jenna surname2', username:'jennasurname2'},
{name: 'Tuija rajala', username:'tuijarajala'}
]
);
const [showSuggestions,setShowSuggestions] = React.useState(false);
const [suggestionList,setSuggestionList] = React.useState(
['johnsmith','jennasurname2','tuijarajala']
);
function onChange(event) {
const regexp = /#[a-zA-Z0-9]*$/;
if (regexp.test(event.target.value)) {
setShowSuggestions(true);
}
else {
setShowSuggestions(false);
}
setInputValue(event.target.value);
}
function focusInput() {
inputRef.current.focus();
}
return(
<React.Fragment>
<input ref={inputRef} type='text' value={inputValue} onChange={onChange}/>
{showSuggestions &&
<Suggestions
inputValue={inputValue}
suggestionList={suggestionList}
applyMention={onChange}
focusInput={focusInput}
/>
}
</React.Fragment>
);
}
function Suggestions(props) {
function selectSuggestion(username) {
const regexp = /#[a-zA-Z0-9]*$/;
const newValue = props.inputValue.replace(regexp,username + ' ');
props.applyMention({target: {value: newValue}}); // THIS MIMICS AN ONCHANGE EVENT
props.focusInput();
}
const suggestionItems = props.suggestionList.map((item) =>
<div className="item" onClick={()=>selectSuggestion('#' + item)}>#{item}</div>
);
return(
<div className="container">
{suggestionItems}
</div>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
.container {
border: 1px solid silver;
width: 150px;
}
.item {
cursor: pointer;
}
.item:hover {
color: blue;
}
input {
width: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
You can simplify your code by doing something like this.
See sandbox: https://codesandbox.io/s/react-example-kgm2h
import ReactDOM from "react-dom";
import React from "react";
class UserMention extends React.Component {
constructor(props) {
super(props);
this.state = {
text: "",
user_list: [
{ name: "John smith" },
{ name: "Jenna surname2" },
{ name: "Tuija rajala" }
],
suggestions: []
};
}
handleOnChange = e => {
const { value } = e.target;
const { user_list } = this.state;
//show all user suggestions
if (value.includes("#") && value.indexOf("#") === value.length - 1) {
this.setState({
text: value,
suggestions: [...this.state.user_list]
});
//show matching user suggesstions
} else if (value.includes("#") && value.length > 1) {
const stringAfterAt = value.slice(value.indexOf("#") + 1).toLowerCase();
const newSuggestions = user_list.filter(user => {
return user.name.toLowerCase().includes(stringAfterAt);
});
this.setState({
text: value,
suggestions: newSuggestions
});
//display no users if they do not use the # symbol
} else {
this.setState({
text: value,
suggestions: []
});
}
};
createSuggestionsList = () => {
const { suggestions } = this.state;
return suggestions.map(user => {
return <div>{user.name}</div>;
});
};
render = () => {
return (
<div>
<input
required
name="text"
value={this.state.text}
onChange={this.handleOnChange}
type="text"
/>
{this.createSuggestionsList()}
{/* <SelectInput value={this.state.suggestions}/> */}
</div>
);
};
}
ReactDOM.render(<UserMention />, document.getElementById("root"));
I'm not entirely sure how you want to render the suggested users, but you can always just pass down this.state.suggestions as a prop to the SelectInput component.
Main takeaway is to use an additional array in our state for suggestions and update it as the user types into the input. We call {this.createSuggestionsList()} inside render to dynamically create the markup for each suggested user. Or as mentioned above, just pass down the suggestions as a prop.

React Input Field logging empty string as first keystroke

I'm not sure what I'm doing wrong, but I have an input field for entering a search term and trying to filter results based on the search term. The problem is that the first value being passed is an empty string and input is offset by 1 item for each keypress after that. For example, if I type 'sea', it would update the search term to be ' se'. Then, when I try to delete the value, it is offset the other direction, so deleting ' se' ends with 's', which can't be deleted.
(Here's a link to the app in progress: https://vibrant-yonath-715bf2.netlify.com/allpokemon. The full search functionality isn't working quite yet. I'm pretty new at this.)
import React, { Component } from 'react';
import Pokemon from './Pokemon';
class PokemonList extends Component {
constructor(props) {
super(props);
this.state = {
pokemonList: [],
searchTerm: '',
fetched: false,
loading: false
};
this.updateResults = this.updateResults.bind(this);
}
componentWillMount() {
this.setState({
loading: true
});
fetch('https://pokeapi.co/api/v2/pokemon?limit=151')
.then(res => res.json())
.then(response => {
this.setState({
pokemonList: response.results,
loading: true,
fetched: true
});
});
}
handleSearchTermChange = (
event: SyntheticKeyboardEvent & { target: HTMLInputElement }
) => {
this.setState({ searchTerm: event.target.value });
this.updateResults();
};
updateResults() {
const filteredList = this.state.pokemonList.filter(
pokemon =>
pokemon.name.toUpperCase().indexOf(this.state.searchTerm.toUpperCase()) >= 0
);
console.log(this.state.searchTerm);
this.setState({
pokemonList: filteredList
});
}
render() {
const { fetched, loading, pokemonList } = this.state;
let content;
if (fetched) {
content = (
<div className="flex-grid">
{pokemonList.map((pokemon, index) => (
<Pokemon key={pokemon.name} id={index + 1} pokemon={pokemon} />
))}
</div>
);
} else if (loading && !fetched) {
content = <p> Loading ...</p>;
} else {
content = <div />;
}
return (
<div>
<input
onChange={this.handleSearchTermChange}
value={this.state.searchTerm}
type="text"
placeholder="Search"
/>
{content}
</div>
);
}
}
export default PokemonList;
setState is asynchronous, so your this.state.searchTerm is not updated when you call updateResults. You could e.g. filter the array in render instead.
Example
class App extends Component {
state = {
pokemonList: [
{ name: "pikachu" },
{ name: "bulbasaur" },
{ name: "squirtle" }
],
searchTerm: ""
};
changeSearchTerm = event => {
this.setState({ searchTerm: event.target.value });
};
render() {
const { pokemonList, searchTerm } = this.state;
const filteredList = pokemonList.filter(pokemon =>
pokemon.name.toUpperCase().includes(searchTerm.toUpperCase())
);
return (
<div>
<input value={searchTerm} onChange={this.changeSearchTerm} />
{filteredList.map(pokemon => <div>{pokemon.name}</div>)}
</div>
);
}
}
I think the problem is that you call this.updateResults();
and then calling this.setState({ searchTerm: event.target.value }); instead of using the callback function for setState.
For example:
this.setState({ searchTerm: event.target.value }, () => this.updateResults());
Hope I got it right.
Update:
Also I see many problems in your code, for example, why you update the list with a filtered list? you don't need to do that:
this.setState({
pokemonList: filteredList
});
Instead of updating the results in the state, you simply need to render the filtered list... meaning your state stay with the original list, also your filterd value, just in the render you pass the filtered list..

Categories