I'm building a dropdown with suggestions that fetch data from an API. The input from the search bar is being stored using setState and it is updated when i change the value in the text input.
The thing is that I'm not managing to update the users lists from the dropdown each time I enter a new character in the text input. Can I somehow force the ponent to be rendered every time the props change? Or is there a better approach?
import React, {useState, useEffect} from 'react';
import Dropdown from '../Dropdown/Dropdown';
import './SearchBar.css';
// Component created with arrow function making use of hooks
const SearchBar = (props) => {
const [input, setInput] = useState('');
const [dropdownComponent, updateDropdown] = useState(<Dropdown input={input}/>)
useEffect(() => {updateDropdown(<Dropdown input={input}/>)}, [input])
const onChange = (e) => {
setInput(e.currentTarget.value)
updateDropdown(<Dropdown input={input}/>)
console.log("=(")
}
return(
<div className="search-bar">
<input type="text" placeholder={props.placeholder} onChange={onChange}/>
{dropdownComponent}
</div>
)
}
export default SearchBar;
I'm building a dropdown with suggestions that fetch data from an API. The input from the search bar is being stored using setState and it is updated when i change the value in the text input.
The thing is that I'm not managing to update the users lists from the dropdown each time I enter a new character in the text input. Can I somehow force the ponent to be rendered every time the props change? Or is there a better approach?
import React, {useState, useEffect} from 'react';
import Dropdown from '../Dropdown/Dropdown';
import './SearchBar.css';
// Component created with arrow function making use of hooks
const SearchBar = (props) => {
const [input, setInput] = useState('');
const [dropdownComponent, updateDropdown] = useState(<Dropdown input={input}/>)
useEffect(() => {updateDropdown(<Dropdown input={input}/>)}, [input])
const onChange = (e) => {
setInput(e.currentTarget.value)
updateDropdown(<Dropdown input={input}/>)
console.log("=(")
}
return(
<div className="search-bar">
<input type="text" placeholder={props.placeholder} onChange={onChange}/>
{dropdownComponent}
</div>
)
}
export default SearchBar;
Share
Improve this question
asked Dec 7, 2019 at 13:02
Felipe SouzaFelipe Souza
1921 gold badge3 silver badges9 bronze badges
2
-
It would help us help you if you included a runnable minimal reproducible example using Stack Snippets (the
[<>]
toolbar button). Stack Snippets support React, including hooks and JSX; here's how to do one. – T.J. Crowder Commented Dec 7, 2019 at 13:05 - * including hooks -- you have to update the version of React, the dropdown list in the UI hasn't been updated in a while. Just pick the latest and then change 16.6.3 to 16.10.2 in the two script tags. – T.J. Crowder Commented Dec 7, 2019 at 13:25
1 Answer
Reset to default 4I can't make the problem happen using your code in a simple test, but your onChange
does have a problem: It's using input
to update the dropdown, but it's not using useCallback
to ensure that input
isn't stale when it does. Either:
Don't update the dropdown in your
onChange
, allowing youruseEffect
callback to do it; orUse
e.target.value
instead ofinput
and get rid of theuseEffect
updating the dropdown; orDon't memoize the dropdown (e.g., don't put it in state) since you want to update it when the input changes anyway, just render it directly in the JSX
Of those, with what you've shown, #3 is probably the simplest:
const SearchBar = (props) => {
const [input, setInput] = useState('');
const onChange = (e) => {
setInput(e.currentTarget.value);
};
return(
<div className="search-bar">
<input type="text" placeholder={props.placeholder} onChange={onChange}/>
<Dropdown input={input}/>
</div>
);
}
Live Example:
const {useState, useEffect} = React;
function Dropdown({input}) {
return <div>Dropdown for "{input}"</div>;
}
const SearchBar = (props) => {
const [input, setInput] = useState('');
const onChange = (e) => {
setInput(e.currentTarget.value);
};
return(
<div className="search-bar">
<input type="text" placeholder={props.placeholder} onChange={onChange}/>
<Dropdown input={input}/>
</div>
);
}
ReactDOM.render(<SearchBar />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare./ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>