防止在基础数据更改时更改下拉选项

Prevent change of dropdown options when underlying data changes

使用以下代码:

<!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>

如何防止在下拉列表更改时减少下拉选项,最好是在不更改 api.data 结构的情况下 ? 我基本上只需要在 api.data returns 新数据时刷新此下拉列表。

是否可能同时保持单一状态(data)?

我已经在下面修改了你的代码。

要点:

  • 删除了 useEffect - API 是静态的,因此不需要 re-allocated
  • useState 仅监视过滤器(API 数据的过滤仅在状态更改时发生,因此不需要存储它 - 但如果需要,您可以使用 Memo 并使其依赖于数据)
  • 选项源自api.data

<!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>

我想不出不使用另一个状态变量的方法。为什么只想要一个变量?

您可以像 Qubaish 所说的那样使用对象状态变量,但这比仅使用第二个状态变量更难维护。

如果您可以使用两个状态变量,请使用以下方法:


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>
    );
};

它只是将options状态下的潜在options复制一份,然后将要显示的数据存储在“data”中。

处理这种情况的一种方法是将状态定义为我在评论中提到的对象。这可能对你有帮助。它对我有用。

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>
  )
}