useSWR 条件获取和 react-boostrap Accordion

问题描述

尝试将 youtube 评论加载到无限加载组件中(使用 npm)

由于无限加载组件是父 Accordion 组件的子组件(来自 react-bootstrap),我试图实现的是仅在 Accordion 获取时使用 useSWR 获取点击(打开)。

我尝试的是使用 useSWR 条件,以便仅在状态“show”为真时获取,这是在函数内部设置的:

const showComments = () => {
    setShow(true)
    if (comments) {
      setCommChunks(_.chunk(comments.comm,10))
      setCommList(commChunks[counter])
    }
  }

调用 Accordion.Toggle onClick 事件。

但是我点击两次手风琴后才能显示评论,这是为什么呢?

我的代码是:

import { useState,useEffect } from 'react'
import { Row,Col,Button,Accordion } from 'react-bootstrap'
import * as _ from 'lodash'
import useSWR from 'swr'
import { MdUnfoldMore } from 'react-icons/md'
import InfiniteScroll from "react-infinite-scroll-component"
import Comments from './Comments'

const siteurl = process.env.NEXT_PUBLIC_SITE_URL

export default function VideoComments({ video }){
    
  const [show,setShow] = useState(false)
  const [counter,setCounter] = useState(0)
  const [commList,setCommList] = useState(null)
  const [commChunks,setCommChunks] = useState([])

  const showComments = () => {
    setShow(true)
    if (comments) {
      setCommChunks(_.chunk(comments.comm,10))
      setCommList(commChunks[counter])
    }
  }

  const fetcher = (...args) => fetch(...args).then(res => res.json())
  const { data: comments,error } = useSWR(show ? `${siteurl}/api/c/${video.id}` : null,fetcher)
  
  // useEffect(() => {
  //   if (comments) {
  //     commChunks = _.chunk(comments.comm,10)
  //     setCommList(commChunks[counter])
  //   }
  // },[comments])

  const fetchMoreData = () => {
    const newCounter = counter + 1;

    // loaded all,return
    if (commChunks[newCounter] === undefined || commChunks[newCounter] == null) {
        return;
    }

    const newCommList = [
        ...commList,...commChunks[newCounter]
    ]
    setCommList(newCommList)
    setCounter(newCounter)
  }

  return (
    <div>
      <Accordion>
        <Row>
          <Col xs={12}>
            <Accordion.Toggle as={Button} onClick={() => {showComments()}} variant="link" eventKey="0"><div><span>Comments</span></div></Accordion.Toggle>
          </Col>
        </Row>
        <Accordion.Collapse eventKey="0">
          <div id="commentsBox" style={{maxHeight: '300px',overflowY: 'auto'}}>
            <Col xs={12}>
              {commList &&
                <InfiniteScroll
                    dataLength={commList.length}
                    next={fetchMoreData}
                    hasMore={true}
                    scrollableTarget="commentsBox"
                >
                  <Comments data={commList} />
                </InfiniteScroll>
              }
            </Col>
          </div>
        </Accordion.Collapse>
      </Accordion>
    </div>
  );
}

编辑:按照下面的建议,我重新激活了useEffect,但它仍然需要点击两次手风琴

const showComments = () => {
    setShow(true)
    if (comments) {
      setCommChunks(_.chunk(comments.comm,10))
      setCommList(commChunks[counter])
    }
  }

  const { data: comments } = useSWR(show ? `${siteurl}/api/c/${video.id}` : null,fetcher)

  useEffect(() => {
    if (comments) {
      setCommChunks(_.chunk(comments.comm,10))
      setCommList(commChunks[counter])
    }
  },[comments])

解决方法

问题出在您的 useEffect 上,在修改 setCommList(commChunks[counter]) 状态后立即调用 commChunks 不会像您想象的那样工作。

您应该将注释保存在块范围变量中,并使用它来连续更新两个状态。

useEffect(() => {
    if (comments) {
        const commentsChunks = _.chunk(comments.comm,10)
        setCommChunks(commentsChunks)
        setCommList(commentsChunks[counter])
    }
},[comments])
,

您评论了处理评论的 useEffect :

  // useEffect(() => {
  //   if (comments) {
  //     commChunks = _.chunk(comments.comm,10)
  //     setCommList(commChunks[counter])
  //   }
  // },[comments])

发生了什么:

  1. 您单击手风琴,showComments 被调用
  2. show 设置为 true,但由于 comments 未定义,commListcommChunks 未设置
  3. 组件重新渲染,现在 useSWR 可以使用 url 获取数据
  4. 组件在获取 si 完成后重新渲染,现在 comments 包含数据
  5. 您第二次点击手风琴,showComments 被调用
  6. show 设置为 true,这次设置了 commListcommChunks
  7. 组件使用 InfiniteScrollComments 重新渲染

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...