为什么 Isotope reloadItems() 在删除元素时会重复元素?

问题描述 投票:0回答:1

我目前正在使用 React、Firebase 实时数据库、Material UI 和 Isotope 库。

我当前面临的问题与添加模式以确认删除注释有关。当我点击“确定!”时为了确认,该注释已从数据库中正确删除,并且 Isotope 重新加载了项目,但它在 UI 中表现出重复效果。然而,在我的数据库中验证后,我确认这些重复的值没有被存储。

这是我的代码:

这是笔记列表

List.jsx

import '@/assets/styles/noteList.css'
import RenderNotes from '@/components/RenderNotes'
import MenuButton from '@/components/buttons/MenuButton'
import SearchButton from '@/components/buttons/SearchButton'
import { auth, db } from '@/services/firebase.config'
import { sortByCreatedAtDate } from '@/utils/helpers'
import AddIcon from '@mui/icons-material/Add'
import { Box, Fab, Stack } from '@mui/material'
import { ref } from 'firebase/database'
import { useEffect, useState } from 'react'
import { useAuthState } from 'react-firebase-hooks/auth'
import { useListVals } from 'react-firebase-hooks/database'
import { Link } from 'react-router-dom'
import { useDebounce } from 'use-debounce'

export default function NoteList () {
  const [notes, setNotes] = useState([])

  const [user] = useAuthState(auth)

  const [search, setSearch] = useState('')
  const [values] = useListVals(ref(db, `note-it-db/${user.uid}/notes`))

  const [debouncedSearch] = useDebounce(search, 300)

  useEffect(() => {
    const filterNotes = values.filter(
      note => note.content.toLowerCase().includes(debouncedSearch.toLowerCase())
    )

    setNotes(
      sortByCreatedAtDate(filterNotes)
    )
  }, [debouncedSearch, values])

  return (
    <Stack>
      <Box className='header'>
        <MenuButton />
        <SearchButton updateSearch={setSearch} />
      </Box>

      <Box className='render-notes-container'>
        <RenderNotes notes={notes} />
      </Box>

      <Fab
        aria-label='add'
        size='medium'
        component={Link}
        to='/notes'
        sx={{
          position: 'fixed',
          bottom: '2rem',
          right: '1rem',
          background: 'linear-gradient(145deg, #5123f8, #8d70f5, #b8a4fe)',
          boxShadow: '5px 5px 10px #3517a1, -5px -5px 10px #bdacfc',
          color: '#ffffff',
          ':hover': {
            background: '#b8a4fe',
            boxShadow: '0 0 5px white'
          },
          transition: 'none',
          zIndex: 1
        }}
      >
        <AddIcon />
      </Fab>
    </Stack>
  )
}

删除Modal.jsx

import { auth, db } from '@/services/firebase.config'
import DeleteIcon from '@mui/icons-material/Delete'
import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Slide } from '@mui/material'
import { ref, remove } from 'firebase/database'
import { forwardRef } from 'react'
import { useAuthState } from 'react-firebase-hooks/auth'

const Transition = forwardRef(function Transition (props, ref) {
  return <Slide direction='up' ref={ref} {...props} />
})

export default function DeleteModal ({ isModalOpen, handleOnClose, elementId }) {
  const [user] = useAuthState(auth)

  const handleDelete = () => {
    const noteRef = ref(db, `note-it-db/${user.uid}/notes/${elementId}`)
    remove(noteRef)
  }

  return (
    <Dialog
      aria-describedby='alert-dialog-slide-description'
      open={isModalOpen}
      TransitionComponent={Transition}
      keepMounted
      onClose={handleOnClose}
      sx={{
        '& .MuiPaper-root': {
          display: 'flex',
          flexDirection: 'column',
          justifyContent: 'space-between',
          alignItems: 'center',
          borderRadius: 'var(--card-border-radius)',
          backgroundColor: 'var(--color-secondary)',
          padding: '1rem'
        }
      }}
    >
      <DialogTitle>
        <DeleteIcon fontSize='large' color='error' />
      </DialogTitle>

      <DialogContent>
        <DialogContentText id='alert-dialog-slide-description' align='center'>
          Are you sure you want to delete this note?
        </DialogContentText>
      </DialogContent>

      <DialogActions className='delete-modal__buttons'>
        <Button
          variant='outlined'
          onClick={handleOnClose}
          sx={{
            color: 'var(--color-primary)',
            borderColor: 'var(--color-primary)',
            borderRadius: 'var(--card-border-radius)',
            textTransform: 'capitalize',
            fontWeight: 'bold',

            '&:hover': {
              borderColor: 'var(--color-primary)',
              backgroundColor: 'rgba(161, 141, 243, 0.15)'
            }
          }}
        >
          No, keep it
        </Button>
        <Button
          variant='contained'
          color='error'
          onClick={handleDelete}
          sx={{
            borderRadius: 'var(--card-border-radius)',
            textTransform: 'capitalize',
            fontWeight: 'bold'
          }}
        >
          Yes, I'm sure
        </Button>
      </DialogActions>
    </Dialog>
  )
}

RenderNotes.jsx

import NoNotesFoundIcon from '@/assets/icons/NoNotesFoundIcon'
import '@/assets/styles/noteList.css'
import Isotope from 'isotope-layout'
import 'isotope-packery'
import { useEffect, useRef } from 'react'
import { useSearchParams } from 'react-router-dom'
import NoteCard from './NoteCard'

const GridLayout = ({ notes }) => {
  const [searchParams] = useSearchParams()
  const filterBy = searchParams.get('filterBy')

  const gridRef = useRef(null)
  const isotopeRef = useRef(null)

  useEffect(() => {
    if (gridRef.current && notes) {
      if (!isotopeRef.current) {
        isotopeRef.current = new Isotope(gridRef.current, {
          layoutMode: 'packery',
          itemSelector: '.grid-item',
          packery: {
            gutter: 8
          },
          filter: filterBy !== null ? `.${filterBy}` : '*'
        })
      } else {
        isotopeRef.current.arrange({ filter: filterBy ? `.${filterBy}` : '*' })
      }
    }

    return () => {
      if (isotopeRef.current) {
        isotopeRef.current.reloadItems()
        isotopeRef.current.arrange({ filter: filterBy ? `.${filterBy}` : '*' })
      }
    }
  }, [filterBy, notes, gridRef, isotopeRef])

  return (
    <div ref={gridRef} className='grid'>
      {
        notes.map(note => (
          <div
            key={note.id}
            className={`grid-item ${note.favorite ? 'favorites' : ''}`}
          >
            <NoteCard note={note} />
          </div>
        ))
      }
    </div>
  )
}

export default function RenderNotes ({ notes }) {
  return notes && notes.length
    ? <GridLayout notes={notes} />
    : <NoNotesFoundIcon />
}

非常感谢您的帮助,我被困在这里一个多月了,幸运的是这是一个个人项目。

我已经尝试使用同位素库中的所有 reloadItems() 和 remove() 方法。

javascript reactjs jquery-isotope
1个回答
0
投票

没关系,伙计们!我正在寻找有关 ChatGPT 的帮助并尝试了很多解决方案,问题是 组件,它导致了不必要的重新渲染。

这是解释:

I'm glad to hear that removing `<React.StrictMode>` fixed the issue! React Strict Mode is a development mode feature that helps catch common mistakes and provides improved behavior for certain functions. It performs additional checks and warnings to help you write better React code.

However, there are cases where these additional checks might trigger warnings or affect the behavior of certain libraries, causing unexpected issues. This is especially true for third-party libraries or code that relies on specific behaviors that are modified in Strict Mode.

In your case, it seems that Isotope or other parts of your code might be interacting with React in a way that triggers warnings or conflicts with the additional checks performed by Strict Mode.

When you remove Strict Mode, those additional checks and warnings are no longer applied, and your application might behave differently. While Strict Mode is valuable for catching issues during development, in some cases, it might be necessary to temporarily disable it or find a workaround for specific scenarios where it interferes with the expected behavior.

If you need to keep using Strict Mode for development, you can consider leaving it enabled and addressing the specific warnings or issues it points out. However, if removing Strict Mode doesn't negatively impact your development workflow, it's acceptable to keep it disabled.

Keep in mind that Strict Mode is primarily a development tool, and its absence won't affect the production build of your application. It's mainly meant to catch potential problems early in the development process.
© www.soinside.com 2019 - 2024. All rights reserved.