问题描述
尝试将 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])
发生了什么:
- 您单击手风琴,
showComments
被调用 -
show
设置为 true,但由于comments
未定义,commList
和commChunks
未设置 - 组件重新渲染,现在
useSWR
可以使用 url 获取数据 - 组件在获取 si 完成后重新渲染,现在
comments
包含数据 - 您第二次点击手风琴,
showComments
被调用 -
show
设置为 true,这次设置了commList
和commChunks
- 组件使用
InfiniteScroll
和Comments
重新渲染