【问题标题】:useSWR conditional fetch and react-boostrap Accordion使用 SWR 条件获取和 react-bootstrap Accordion
【发布时间】:2021-01-31 18:43:07
【问题描述】:

尝试将 youtube cmets 加载到无限加载组件中(使用 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 两次后才能显示 cmets,这是为什么呢?

我的代码是:

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

【问题讨论】:

    标签: reactjs next.js react-bootstrap infinite-scroll swr


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

      您评论了处理 cmets 的 useEffect

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

      会发生什么:

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

      【讨论】:

      • 我评论了它,因为它是一个测试,它也不能与它一起工作,我还尝试摆脱 setShow 并直接在 useSWR 中使用函数 showComments 作为触发器,就像他们的文档示例一样,但它是一样的,你建议什么?
      • 我试图重新激活你所看到的 useEffect(但使用 setCommChunks 作为函数),并使用 showComments() 直接摆脱“显示”状态,它在它显示的意义上起作用cmets 在第一次点击时,问题是它在页面加载时调用 useSWR,而不是在 Accordion 点击​​时调用
      • 保持原样的“显示”状态和useSWR(show ?
      • 你能提供codesandbox.io中的例子吗?
      • 已更新,按照建议使用 show 和 useEffect,仍然需要点击两次
      猜你喜欢
      • 1970-01-01
      • 2021-10-24
      • 2017-02-19
      • 2021-01-18
      • 2021-06-14
      • 1970-01-01
      • 2021-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多