【问题标题】:How can I avoid updating all instances of my function component with the useState hook in React.js?如何避免使用 React.js 中的 useState 挂钩更新我的功能组件的所有实例?
【发布时间】:2020-03-25 22:35:54
【问题描述】:

TL;DR 我正在制作一个可重用的Button 功能组件。我的按钮标签的useState() 钩子正在更新每个Button 实例。我怎样才能防止这种情况发生?

我对 React 非常陌生,并且为了学习而构建了一个 Book Finder 应用程序。到目前为止,我的应用程序有一个 BookList 和一个 ReadingList。任一列表中的每个BookDetail 都有一个Button,用于在ReadingList 中添加/删除该书。添加/删除功能有效(呸),但使用useState 更新Button 的标签会更新Button 组件的每个实例,而不仅仅是被点击的那个。

ButtonsBookList 中的书籍上以标签“添加到阅读列表”开头,但如果我点击其中的任何,它们中的所有都会更新为'从阅读列表中删除'。

我尝试将逻辑移动到 Button 组件或 List 组件中,但我最终破坏了该功能。

App.js

function App() {

const books = useState([])
const [booksToRead, setBooksToRead] = useState([])
const [addRemove, setAddRemove] = useState(true)
const [label, setLabel] = useState('Add to Reading List')

function handleAddBook(book) {
    const newID = book.title_id
    if( (typeof booksToRead.find(x => x.title_id === newID)) == 'undefined' ) {
        setBooksToRead([...booksToRead, book])  
    }
}

function handleRemoveBook(book) {
    console.log(book)
    const array = booksToRead
    const index = array.indexOf(book)
    const newArray = [...array.slice(0, index), ...array.slice(index +1)]
    setBooksToRead(newArray)
}

function addOrRemove(book) {
    if( addRemove ) {
        handleAddBook(book)
        setLabel('Remove from Reading List')
        setAddRemove(false)
    } else {
        handleRemoveBook(book)
        setLabel('Add to Reading List')
        setAddRemove(true)
    }
}

return (
    <main>
        <BookList books={books} handleAddBook={handleAddBook} addOrRemove={addOrRemove} label={label} />
        <ReadingList booksToRead={booksToRead} handleRemoveBook={handleRemoveBook} />
    </main>
  );
}

export default App;

BookList.js

function BookList ({ book, label, handleAddBook, addOrRemove }) {

    return (
        <div className="booklist">
            {BookData.map((book, index) => {

                const onAddBook = () => addOrRemove(book)

                return (
                <div key={index} className="card">
                    <BookDetail key={book.title_id} book={book} />
                    <Button key={index + 'btn'} label={label} onClick={onAddBook} />
                </div>
                )
            })}
        </div>
    )
}

export default BookList

最后是 Button.js

export default function Button({ styleClass, label, onClick }) {

    return (
        <button className='btn' onClick={(event) => onClick(event)}>
            {label}
        </button>
    )
}

codesandbox 中的无样式示例:https://codesandbox.io/s/cool-rgb-fksrp

【问题讨论】:

    标签: javascript reactjs react-hooks instance react-component


    【解决方案1】:

    您能否进行这些更改,如果有任何进展,请告诉我:

    1. &lt;Button label={label} onClick={() =&gt; addOrRemove(book)} /&gt;
    2. &lt;button className='btn' onClick={onClick}&gt;

    看起来在 button 中,您传递的是 event 而不是 book 作为函数参数

    【讨论】:

    • 功能仍然有效,但每个按钮实例仍在更新:/
    • 是的,这是有道理的。让Button 组件移动到BookDetail 组件中。还将onClick 属性添加到BookDetail 组件。让我知道你是否正在取得进展。注:从BookList 组件中删除Button
    • 好的,现在该功能仍然有效,但标签没有改变。进步了?!
    • 你也可以在const index = array.indexOf(book)下方添加console.log(index)。我不确定您是否正确获取索引
    • 这里非常简化,工作示例:codesandbox.io/s/vigorous-stallman-xsu0u。我如何看待您发布的示例的问题很难跟踪和同步状态。所有书籍都没有存储在状态中,而是存储在 JSON 文件中(使用 BookList 组件)。比你有另一个ReadingList 组件列表。拥有单一书籍列表可以减少错误的表面错误。我在提供的示例中所做的只是在所选书籍上切换inReadList 属性。所以要处理的数据更少,管理的辅助函数更少,需要维护的状态也更少
    【解决方案2】:

    就像现在一样,您声明一个标签并在所有书籍条目上使用相同的标签。这就是为什么它们都显示相同的标签。您需要跟踪每本书的标签,例如将标签作为字段保存在书对象中。

    例如:

    const books = useState([{ label: 'Add to reading list', addRemove: true }])
    

    然后:

    function addOrRemove(book) {
        if( book.addRemove ) {
            handleAddBook(book)
            book.label = 'Remove from Reading List'
            book.addOrRemove = false
        } else {
            handleRemoveBook(book)
            book.label = 'Add to Reading List'
            book.addOrRemove = true
        }
    }
    

    这样,每本书都有自己的标签。

    【讨论】:

    • 感谢您的回答;我认为您的意思是 if/else 中的book.addRemove。我试过你的建议,但现在标签根本没有改变,功能也不起作用。
    猜你喜欢
    • 2020-06-10
    • 1970-01-01
    • 1970-01-01
    • 2020-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-27
    相关资源
    最近更新 更多