导航到另一页时,next / link丢失状态

时间:2020-09-01 13:07:42

标签: javascript reactjs next.js react-state

我正在开发 Next.js应用程序。出于这个问题的目的,我在应用程序中有两个页面: BooksPage (列出所有书籍)和 BookPage (用于呈现书籍的详细信息)。在组件方面,我有一个<Books />组件,它为我的图书馆数据库中的每本书提供了一个<Book />组件。

这是我的组成部分:

Books.js

function Books({ books }) {
  return (
    <>
      {books.map(book => (
        <Book key={book.id} book={book} />
      ))}
    </>
  );
}

Book.js

class Book extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state = { liked: false };
  }

  like = () => {
    this.setState({ liked: this.state.liked ? false : true })
  };

  render() {
    return (
      <>
        <Link href={`/books/${book.slug}`}>
          <a>{book.title}</a>
        </Link>

        <Button onClick={this.like}>
          <LikeIcon
            className={this.state.liked ? "text-success" : "text-dark"}
          />
        </Button>
      </>
    );
  }
}

问题:

说我在 BooksPage 页面上。当我单击<Book />的“赞”按钮时,图标颜色在前端正确切换,并且在后端成功添加或删除了类似颜色。当我刷新 BooksPage 时,所有状态都保持不变。

当我喜欢 BooksPage 上的内容,然后立即导航到 BookPage 而不使用next / link刷新时,就会出现问题。那里的“赞”按钮未始终切换,并且 BooksPage 的状态丢失。请注意,如果我硬刷新页面,一切都会恢复正常。

慢速解决方案:请勿使用next / link。

替换

<Link href={`/books/${book.slug}`}>
  <a>{book.title}</a>
</Link>

使用

<a href={`/books/${book.slug}`}>{book.title}</a>

快速解决方案:继续使用下一个/链接吗?

导航到另一条预渲染的路线时,是否可以使用next / link并保持状态?

4 个答案:

答案 0 :(得分:2)

您需要使用Model.refresh_from_db(...)--(Django Doc)方法来 从数据库中检索更新的值

class DeleteLikeView(APIView):

    def post(self, request, book):
        book = get_object_or_404(Book, id=book)
        print(book.num_of_likes)
        like = Like.objects.get(user=request.user, book=book)
        like.delete()

        book.refresh_from_db()  # here is the update
        
        print(book.num_of_likes)  # You will get the updated value
        return ...

答案 1 :(得分:1)

TLDR:每当需要更改按钮时,API都必须更改数据,并且必须更新最接近父级的本地状态以更新button的外观。 API将控制本地状态的各个方面。除非API请求成功,否则您无法更新本地状态。因此,客户端和API始终为1:1。

Book.js 中的Button组件应与API数据分开维护其自身状态;相反,无论您从API那里获取book数据,它也应该控制按钮的状态(及其外观)。为什么?因为使用当前方法,API请求可能会失败,但是客户端仍将更新。结果,API和客户端可能不再是1:1(客户端显示喜欢,但API仍然显示不喜欢/不喜欢)。

在实践中,您将有一个充当状态管理器的父容器。它获取所有相关数据,处理数据更新,并使用 stateless 子组件显示结果。每当需要更新子组件时(例如,通过按下按钮显示“喜欢”或“不喜欢”按钮),它都必须首先发出API请求以更改数据,然后API必须以相关数据响应更新孩子使用的状态:

enter image description here

或者,如果该组件是可重用的,那么您将有条件地使用this.props.book(来自父容器)来呈现它,或者子组件必须从API请求数据以更新其自身的本地{{1 }}。与上图相同,API请求控制状态更改的所有方面:

enter image description here

还有另一种与上图相同的方法,但是它使用子级本地状态,而不管父级状态如何。此子状态将仅通过其自己的类方法进行更新。这带来了更多的复杂性,因为您必须确保任何父状态更改不会用陈旧的数据重新呈现子组件。最终,哪种方法取决于您。

附带说明:由于 不会呈现页面,也不会尝试内部页面导航。相反,它们提供了可重复使用的组件,这些组件可以被一个或多个NextJS项目页面或组件使用。

答案 2 :(得分:1)

以某种方式通过API传递书籍的liked属性。然后,将该道具从Books组件传递到Book组件。

向您的图书组件添加componentDidUpdate()方法。

class Book extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state = { liked: this.props.liked };
  }

  componentDidUpdate(prevProps) {
    if (this.props.liked !== prevProps.liked) {
      this.setState({
        liked: this.props.liked,
      });
    }
  }

  like = () => {
    this.setState({ liked: !this.state.liked })
  };

  render() {
    return (
      <>
        <Link href={`/books/${book.slug}`}>
          <a>{book.title}</a>
        </Link>

        <Button onClick={this.like}>
          <LikeIcon
            className={this.state.liked ? "text-success" : "text-dark"}
          />
        </Button>
      </>
    );
  }
}

答案 3 :(得分:0)

在DeleteLikeView类中,您获得书本对象。它从数据库检索并保存在book变量中。 当您删除类似对象的对象时,数据库中的num_of_likes属性已更新,但您的变量仍包含先前的对象。在like.delete()命令之后,您应该再次获取对象并打印num_of_likes att。符合您的预期。