Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/449.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 反应由交叉点观察者引起的内存泄漏_Javascript_Reactjs_Memory Leaks_Garbage Collection_Google Chrome Devtools - Fatal编程技术网

Javascript 反应由交叉点观察者引起的内存泄漏

Javascript 反应由交叉点观察者引起的内存泄漏,javascript,reactjs,memory-leaks,garbage-collection,google-chrome-devtools,Javascript,Reactjs,Memory Leaks,Garbage Collection,Google Chrome Devtools,背景信息:我的React应用程序在手机上崩溃。Chrome开发工具表明没有触发垃圾回收。查看堆,按保留大小排列的顶级构造函数都引用了intersection observor(在我的许多react组件中用于无限滚动) 问题:我如何着手修复由交叉点观察者造成的内存泄漏?有没有一种方法可以在组件卸载时触发垃圾收集 使用交叉点观测器进行无限滚动的示例组件: import React, { useEffect, useState, useRef, useCallback } from 'react' i

背景信息:我的React应用程序在手机上崩溃。Chrome开发工具表明没有触发垃圾回收。查看堆,按保留大小排列的顶级构造函数都引用了intersection observor(在我的许多react组件中用于无限滚动)

问题:我如何着手修复由交叉点观察者造成的内存泄漏?有没有一种方法可以在组件卸载时触发垃圾收集

使用交叉点观测器进行无限滚动的示例组件:

import React, { useEffect, useState, useRef, useCallback } from 'react'
import { Link } from 'react-router-dom'
import { uuid, fabricateTimeStamp, getRandom } from '../containers/helperFunctions'
import { avatarQuery } from '../words'
import quote from 'inspirational-quotes'
import history from '../history'
import { thumbsUp, thumbsDown, arrowDrop } from './svgs'
import { 
  fetchAvatars as callAvatarsAPI, 
  fetchVideos as callVideosAPI } from '../containers/api'

const ActivityFeed = (props) => {
  const [firstRenderDone, setFirstRenderDone] = useState()
  const [comments, setComments] = useState([])

  useEffect(() => {
    const mobile = window.innerWidth <= 600
    if (mobile) fetchAvatars('woman', 3)
    if (!mobile) fetchAvatars('woman', 6)
    if (history.location.pathname.includes('/video/') || history.location.pathname.includes('/search/')) {
      document.querySelector('.activityFeedContainer').classList.toggle('hide')
    }
  }, [])

  // if user clicks nav button, remove all comments generated by infinite scroll
  useEffect(() => {
    setComments(prevState => (prevState.slice(0, 8)))
  }, [props.button])

  // INFINITE SCROLL
  // Callback is triggered when ref is set in mapCommentsToHTML
  const observer = useRef()
  const lastActivityPost = useCallback(lastPostNode => {
    observer.current = new IntersectionObserver(entries => {
      const lastPost = entries[0]
      if (lastPost.isIntersecting) fetchAvatars(getRandom(avatarQuery), 6)
    })
    if (lastPostNode) observer.current.observe(lastPostNode)
  })

  const fetchAvatars = async (query, amount) => {
    let response = await callAvatarsAPI(query, amount)
    response = response.data.hits
    mapCommentsToHTML(response)
  }

  const mapCommentsToHTML = (response) => {
    const picsMappedToHTML = response.map((pic, index) => {
      return ( 
        <div className="commentWrapper" key={uuid()} ref={response.length === index + 1 ? lastActivityPost : null}>
          <div className="avatarPlaceholder--comments">
          {props.page === 'channel' 
            ? <img 
                className="avatarPlaceholder--img" 
                src={
                  props.userAvatar.previewURL ? props.userAvatar.previewURL 
                  : props.userAvatar.userImageURL === "" ? 'https://i.imgur.com/ZwDgXSF.jpg' 
                  : props.userAvatar.userImageURL}
                alt="An Activity Feed User Avatar" />

            : <Link to={`/channel/${pic.id}`}> 
                <img 
                  className="avatarPlaceholder--img" 
                  src={pic.previewURL}
                  alt="An Activity Feed User Avatar" />
              </Link>
          }
          </div>
          <div className="commentContainer" >
            <Link to={`/channel/${pic.id}`}> 
              <h5 className="commentorName">{props.page === 'channel' ? props.userName : pic.user}</h5>
            </Link>
            <span className="dateOfComment">{fabricateTimeStamp(index)}</span> 
            <p className={`${props.page}-comment`}>{quote.getQuote().text}</p>
            <div className="thumbs">
              <span className="thumbsUpIcon">
                {thumbsUp(16)}
              </span>
              <span className="thumbsDownIcon">
                {thumbsDown(16)}
              </span>
            </div>
            <p className="replyText">REPLY</p>
            <div className="viewReplies">
              <span className="arrowDrop">
                {arrowDrop()}
              </span>
              View {Math.floor(Math.random() * 50) + 2} Replies
            </div>
          </div>
        </div>
      )
    })
    setComments(prevState => ([...prevState, ...picsMappedToHTML]))
  }

  return (
    <aside className="activityFeedContainer">
      <h1 className={`${props.page}--activity-feed-title`}>Activity Feed</h1>
      <hr className="home--activityfeed-hr" />
      <div className="commentSection--activityfeed">
        {comments}
      </div>
    </aside>
  )
}
export default ActivityFeed
import React,{useffect,useState,useRef,useCallback}from'React'
从“react router dom”导入{Link}
从“../containers/helperFunctions”导入{uuid,factureTimeStamp,getRandom}
从“../words”导入{avatarQuery}
从“励志格言”导入格言
从“../history”导入历史记录
从“/svgs”导入{thumbsUp、thumbsDown、arrowDrop}
导入{
获取头像作为callAvatarsAPI,
从“../containers/api”以callVideosAPI}的形式获取视频
const ActivityFeed=(道具)=>{
const[firstRenderDone,setFirstRenderDone]=useState()
const[comments,setComments]=useState([])
useffect(()=>{
const mobile=window.innerWidth{
setComments(prevState=>(prevState.slice(0,8)))
},[props.按钮])
//无限卷轴
//在mapCommentsToHTML中设置ref时触发回调
const observer=useRef()
const lastActivityPost=useCallback(lastPostNode=>{
observer.current=新的IntersectionObserver(条目=>{
const lastPost=条目[0]
如果(lastPost.isIntersecting)获取头像(getRandom(avatarQuery),6)
})
if(lastPostNode)observer.current.observe(lastPostNode)
})
const fetchAvatars=async(查询,金额)=>{
let response=wait callAvatarsAPI(查询,金额)
response=response.data.hits
mapCommentsToHTML(响应)
}
常量mapCommentsToHTML=(响应)=>{
const picsMappedToHTML=response.map((pic,index)=>{
报税表(
{props.page==='channel'
? 
:  
}
{props.page==='channel'?props.userName:pic.user}
{factureTimeStamp(索引)}

{quote.getQuote().text}

{thumbsUp(16)} {thumbsDown(16)} 回复

{arrowDrop()} 查看{Math.floor(Math.random()*50)+2}回复 ) }) setComments(prevState=>([…prevState,…picsMappedToHTML])) } 返回(

堆快照:

import React, { useEffect, useState, useRef, useCallback } from 'react'
import { Link } from 'react-router-dom'
import { uuid, fabricateTimeStamp, getRandom } from '../containers/helperFunctions'
import { avatarQuery } from '../words'
import quote from 'inspirational-quotes'
import history from '../history'
import { thumbsUp, thumbsDown, arrowDrop } from './svgs'
import { 
  fetchAvatars as callAvatarsAPI, 
  fetchVideos as callVideosAPI } from '../containers/api'

const ActivityFeed = (props) => {
  const [firstRenderDone, setFirstRenderDone] = useState()
  const [comments, setComments] = useState([])

  useEffect(() => {
    const mobile = window.innerWidth <= 600
    if (mobile) fetchAvatars('woman', 3)
    if (!mobile) fetchAvatars('woman', 6)
    if (history.location.pathname.includes('/video/') || history.location.pathname.includes('/search/')) {
      document.querySelector('.activityFeedContainer').classList.toggle('hide')
    }
  }, [])

  // if user clicks nav button, remove all comments generated by infinite scroll
  useEffect(() => {
    setComments(prevState => (prevState.slice(0, 8)))
  }, [props.button])

  // INFINITE SCROLL
  // Callback is triggered when ref is set in mapCommentsToHTML
  const observer = useRef()
  const lastActivityPost = useCallback(lastPostNode => {
    observer.current = new IntersectionObserver(entries => {
      const lastPost = entries[0]
      if (lastPost.isIntersecting) fetchAvatars(getRandom(avatarQuery), 6)
    })
    if (lastPostNode) observer.current.observe(lastPostNode)
  })

  const fetchAvatars = async (query, amount) => {
    let response = await callAvatarsAPI(query, amount)
    response = response.data.hits
    mapCommentsToHTML(response)
  }

  const mapCommentsToHTML = (response) => {
    const picsMappedToHTML = response.map((pic, index) => {
      return ( 
        <div className="commentWrapper" key={uuid()} ref={response.length === index + 1 ? lastActivityPost : null}>
          <div className="avatarPlaceholder--comments">
          {props.page === 'channel' 
            ? <img 
                className="avatarPlaceholder--img" 
                src={
                  props.userAvatar.previewURL ? props.userAvatar.previewURL 
                  : props.userAvatar.userImageURL === "" ? 'https://i.imgur.com/ZwDgXSF.jpg' 
                  : props.userAvatar.userImageURL}
                alt="An Activity Feed User Avatar" />

            : <Link to={`/channel/${pic.id}`}> 
                <img 
                  className="avatarPlaceholder--img" 
                  src={pic.previewURL}
                  alt="An Activity Feed User Avatar" />
              </Link>
          }
          </div>
          <div className="commentContainer" >
            <Link to={`/channel/${pic.id}`}> 
              <h5 className="commentorName">{props.page === 'channel' ? props.userName : pic.user}</h5>
            </Link>
            <span className="dateOfComment">{fabricateTimeStamp(index)}</span> 
            <p className={`${props.page}-comment`}>{quote.getQuote().text}</p>
            <div className="thumbs">
              <span className="thumbsUpIcon">
                {thumbsUp(16)}
              </span>
              <span className="thumbsDownIcon">
                {thumbsDown(16)}
              </span>
            </div>
            <p className="replyText">REPLY</p>
            <div className="viewReplies">
              <span className="arrowDrop">
                {arrowDrop()}
              </span>
              View {Math.floor(Math.random() * 50) + 2} Replies
            </div>
          </div>
        </div>
      )
    })
    setComments(prevState => ([...prevState, ...picsMappedToHTML]))
  }

  return (
    <aside className="activityFeedContainer">
      <h1 className={`${props.page}--activity-feed-title`}>Activity Feed</h1>
      <hr className="home--activityfeed-hr" />
      <div className="commentSection--activityfeed">
        {comments}
      </div>
    </aside>
  )
}
export default ActivityFeed

我认为你需要在某个时候停止观察,你可能想


卸载时调用IntersectionObserver我认为您需要在某个时候停止观察,您可能希望


理想情况下,当您卸载时调用IntersectionObserver,我会将IntersectionObserver放在useEffect钩子中,当组件卸载时,我会调用Observer.unobserve()理想情况下,我会将IntersectionObserver放在useEffect钩子中,当组件卸载时,我会调用Observer.unobserve()