React状态在与复合对象一起使用时会重置。

huangapple go评论61阅读模式
英文:

React state resets when used with a composite object

问题

在React中,您遇到的问题似乎与状态管理有关。当您使用setBook更新book状态时,它不会保留旧状态的引用,而是创建一个新的状态对象。因此,在setContent中使用setBook({ ...book, content })时,它实际上是创建一个新的book对象,其中只有content字段发生更改,而title字段仍然保持不变。

解决这个问题的一种方法是在setContent中确保您在新状态对象中保留旧的title值。这样,它不会被重置为空字符串。以下是修改后的setContent函数:

function setContent(content: string) {
  setBook({ ...book, content, title: book.title })
}

这样做可以确保在更新content字段时不会丢失title字段的值。

另一种方法是,您可以将初始状态设置为null,然后在渲染BookComponent时检查book是否为null,如果是,就返回一个空字符串作为默认值。这种方法允许book在初始化时为null,然后在加载后更新为实际的Book对象。

希望这有助于解决您的问题。

英文:

I'm new to React. Here is the scenario:

  • I have a class called Book. A book has a title and content, both strings.
  • I'm trying to separate the concerns within the book page into a BookComponent (view) and Book hook (state) and a Book class (dealing with the backend API), similar to what's described here: https://martinfowler.com/articles/modularizing-react-apps.html

Here is a sample code:

export const useBook = () => {
  const [book, setBook] = React.useState<Book>(new Book('', ''))
 
  function load(id: string) {
    Book.fetch(id).then((book) => { setBook(book) })
  }
  
  function title() : string {
     return book.title
  }

  function content() : string {
     return book.content 
  }

  function setTitle(title: string) {
    setBook({ ...book, title })
  }

  function setContent(content: string) {
    setBook({ ...book, content })
  }

  return {
    title,
    setTitle,
    content,
    setContent
  }
}

In the BookComponent (view) I have this:

<div>{book.title()}</div>
<input type="text" value={book.content()} onChange={(e) => book.setContent(e.target.value) }} />

(Omitted useEffect code to load the book)

The page shows the title and the content correctly. However, as soon as I type anything in the textbox, the title goes back to "" which is the initial value of the state.

I thought using setBook({...book, content}) within the hook is going to copy the existing book state and only modify content, but it seems the code enters setContent with a brand new book when I inspect ...book

Changing the state to the following fixes the problem:

const [book, setBook] = React.useState<Book | null>(null)
// ...
function title() : string {
 if (!book) return { '' }
 
 return book.title
}
// same for content

But I don't understand why the state would start from a null value (default) every time and the lifecycle of it.

答案1

得分: 1

将新状态设置为以下方式(带有回调函数),在setContent(以及在setTitle中同样如此)中,可以访问先前的状态,并且它应该与您的预期完全一致。使用展开运算符复制prevState到一个新状态并覆盖content

setBook(prevState => ({ ...prevState, content }))
英文:

Set your new state like this (with a callback fn) inside your setContent (and similarly in setTitle) with an access to previous state and it should work exactly as you expected. Copy prevState with spread operateor into a new state and override content:

setBook(prevState => ({ ...prevState, content }))

huangapple
  • 本文由 发表于 2023年2月10日 03:15:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/75403394.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定