Reputation: 3813
With the code below:
<!DOCTYPE html>
<html>
<body>
<head>
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<style>
</style>
</head>
<body>
<div id="root">
</body>
<script type="text/babel">
const api = {
data: [
{
id: 1, party: 'Zuckerberg', news: [
{id: 1, headline: 'Zuckerberg news1'},
{id: 2, headline: 'Zuckerberg news2'},
]
},
{
id: 2, party: 'Musk', news: [
{id: 1, headline: 'Musk news1'},
{id: 2, headline: 'Musk news2'},
]
},
]
}
const App = () => {
const [data, setData] = React.useState([])
React.useEffect(() => setData(api.data), [])
const handleSelectChange = (e) => {
const name = e.target.value
setData(prev => prev.filter(datum => datum.party === name))
}
return (
<div>
<select
onChange={handleSelectChange}>
{data.map(datum => <option key={datum.id}>{datum.party}</option>)}
</select>
{data.map(
datum =>
datum.news.map(newsItem =>
<div key={newsItem.id}>{newsItem.headline}</div>
)
)}
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
</script>
</html>
how can I prevent the reduction of dropdown options upon dropdown change, preferably without changing the api.data
structure?
I basically need this dropdown to be refreshed only when api.data
returns new data.
Is it possibly while keeping only single state (data
)?
Upvotes: 0
Views: 35
Reputation: 728
One way to handle this scenario by define state as an object like I mentioned in my comment. This might help you. It's working for me.
const MyComponent = () => {
const [data, setData] = React.useState({})
React.useEffect(() => setData({dropdownValues: api.data, filteredValues: api.data}), [])
const handleSelectChange = (e) => {
const name = e.target.value
const filteredValues = data.dropdownValues.filter(datum => datum.party === name);
setData({...data, filteredValues})
}
return (
<div>
<select
onChange={handleSelectChange}>
{data.dropdownValues && data.dropdownValues.map(datum => <option key={datum.id}>{datum.party}</option>)}
</select>
{data.filteredValues && data.filteredValues.map(
datum =>
datum.news.map(newsItem =>
<div key={newsItem.id}>{newsItem.headline}</div>
)
)}
</div>
)
}
Upvotes: 1
Reputation: 154
I can't think of a way to do it without using another state variable. What's the reason for only wanting one variable?
You could use an object state variable as Qubaish said but that can be much more difficult to maintain than just using a second state variable.
If you can get away with using two state variables use the following:
const App = () => {
const [data, setData] = React.useState([]);
const [options, setOptions] = useState([]);
React.useEffect(() => {
setData(api.data);
setOptions(api.data);
}, []);
const handleSelectChange = (e) => {
let name = e.target.value;
setData(options.filter((datum) => datum.party === name));
};
return (
<div>
<select onChange={handleSelectChange}>
{options.map((datum) => (
<option key={datum.id}>{datum.party}</option>
))}
</select>
{data.map((datum) =>
datum.news.map((newsItem) => (
<div key={newsItem.id}>{newsItem.headline}</div>
))
)}
</div>
);
};
It just stores a copy of the potential options in the options state and then stores the data to be displayed in "data".
Upvotes: 0
Reputation: 535
I've modified your code below.
Main points:
<!DOCTYPE html>
<html>
<body>
<head>
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<style>
</style>
</head>
<body>
<div id="root">
</body>
<script type="text/babel">
const api = {
data: [
{
id: 1, party: 'Zuckerberg', news: [
{id: 1, headline: 'Zuckerberg news1'},
{id: 2, headline: 'Zuckerberg news2'},
]
},
{
id: 2, party: 'Musk', news: [
{id: 1, headline: 'Musk news1'},
{id: 2, headline: 'Musk news2'},
]
},
]
}
const App = () => {
const [data, setData] = React.useState(api.data.length?api.data[0].party:undefined)
const handleSelectChange = (e) => {
setData(e.target.value)
}
return (
<div>
<select
onChange={handleSelectChange}>
{api.data.map(datum => <option key={datum.id}>{datum.party}</option>)}
</select>
{api.data.filter(datum=>datum.party===data).map(
datum =>
datum.news.map(newsItem =>
<div key={newsItem.id}>{newsItem.headline}</div>
)
)}
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
</script>
</html>
Upvotes: 0