0

尝试将 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 事件上调用。

但是,我只能在单击 Accordion 两次后才能显示评论,这是为什么呢?

我的代码是:

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,但它仍然需要两次点击Accordion

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])
4

2 回答 2

1

问题出在您的,在修改状态后立即useEffect调用不会有更新的值。在 React 中设置状态是一个异步操作(请参阅React setState not updated immediate)。setCommList(commChunks[counter])commChunks

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

useEffect(() => {
    if (comments) {
        const commentsChunks = _.chunk(comments.comm, 10)
        setCommChunks(commentsChunks)
        setCommList(commentsChunks[counter])
    }
}, [comments])
于 2021-02-03T22:37:25.813 回答
0

您评论了useEffect处理评论的:

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

怎么了 :

  1. 你点击手风琴,showComments被称为
  2. show设置为 true,但因为comments未定义,commList并且commChunks未设置
  3. 组件重新渲染,现在useSWR可以使用 url 获取数据
  4. 提取 si 完成后组件重新渲染,现在comments包含数据
  5. 你第二次点击 Accordion,showComments被称为
  6. show设置为真,这一次commListcommChunks设置
  7. InfiniteScroll组件使用and重新渲染Comments
于 2021-02-03T04:48:21.143 回答