В настоящее время я пытаюсь включить модальную функцию всплывающего окна, которую мне удалось сделать, и она работает, однако теперь я пытаюсь создать ту же самую функцию внутри хука useEffect, чтобы она не выполняла повторный рендеринг каждый раз. На данный момент я попробовал несколько методов, и ничего не помогло. Вот мой код:
AppContent.jsx (без useEffect):
import React, { useState, useEffect } from 'react'
import { X } from 'lucide-react'
import { AnimatePresence } from 'framer-motion';
import AppForm from './AppForm';
const AppContent = () => {
const [ applicationOpen, setApplicationOpen ] = useState(false);
const close = () => setApplicationOpen(false);
const open = () => setApplicationOpen(true);
return (
<>
<button
className='apply-btn'
onClick = {() => applicationOpen ? close() : open()}
>
APPLY HERE
</button>
<AnimatePresence>
{applicationOpen && <AppForm applicationOpen = {applicationOpen} handleClose = {close}/>}
</AnimatePresence>
</>
)
}
export default AppContent
Код выше работает отлично.
AppContent.jsx (с useEffect):
import React, { useState, useEffect } from 'react'
import { X } from 'lucide-react'
import { AnimatePresence } from 'framer-motion';
import AppForm from './AppForm';
const AppContent = () => {
const [ applicationOpen, setApplicationOpen ] = useState(false);
useEffect(() => {
const close = () => setApplicationOpen(false);
const open = () => setApplicationOpen(true);
close();
open();
},[]);
return (
<>
<button
className='apply-btn'
onClick = {() => applicationOpen ? close() : open()}
>
APPLY HERE
</button>
<AnimatePresence>
{applicationOpen && <AppForm applicationOpen = {applicationOpen} handleClose = {close}/>}
</AnimatePresence>
</>
)
}
export default AppContent
Может ли кто-нибудь помочь мне, пожалуйста, и указать, что я делаю неправильно? Спасибо.
С первым кодом, которым вы поделились, проблем нет. Вы делаете AppForm условным и уже позаботились об этом. Если нет, вы также можете переместить AnimatePresence
внутри состояния. Так.
return (
<>
<button className = "apply-btn" onClick = {() => (applicationOpen ? close() : open())}>
APPLY HERE
</button>
{applicationOpen && (
<AnimatePresence>
<AppForm applicationOpen = {applicationOpen} handleClose = {close} />
</AnimatePresence>
)}
</>
);
И использование useEffect
во втором примере совершенно неверно. Вот как useEffect
работает. Вы дарите два реквизита useEffect
.
Всякий раз, когда реквизиты или состояния, которые вы указываете в массиве зависимостей, изменяются, вызывается указанная вами функция. Он также вызывался при запуске. Это когда компонент смонтирован.
Итак, ваша функция внутри useEffect
вызывается в начале и закрывает AppForm
, а затем открывает его. И поскольку вы определили свои функции open
и close
внутри useEffect
, они становятся недоступными извне. Для получения дополнительной информации о useEffect
перейдите по ссылке .
Если вы хотите открыть AppForm
при запуске, используйте что-то вроде этого.
import React, {useState, useEffect} from 'react';
import {X} from 'lucide-react';
import {AnimatePresence} from 'framer-motion';
import AppForm from './AppForm';
const AppContent = () => {
const [applicationOpen, setApplicationOpen] = useState(false);
const close = () => setApplicationOpen(false);
const open = () => setApplicationOpen(true);
useEffect(() => {
open();
}, []);
return (
<>
<button className = "apply-btn" onClick = {() => (applicationOpen ? close() : open())}>
APPLY HERE
</button>
<AnimatePresence>
{applicationOpen && <AppForm applicationOpen = {applicationOpen} handleClose = {close} />}
</AnimatePresence>
</>
);
};
export default AppContent;
Спасибо за предложение. Я все еще новичок в использованииEffects, так как мне не приходилось использовать его так часто. Причина, по которой я хотел использовать useEffect
в этом случае, заключается в том, что когда я впервые создал эту функцию, я получил сообщение об ошибке «слишком много повторных рендерингов», и я знаю, что вы можете использовать useEffect
, чтобы избежать этого. В любом случае, спасибо.
Это должно быть потому, что вы изначально пытались вызвать функцию close
или open
непосредственно на кнопке onClick
. например onClick = {open()}
Это приведет к ошибке, о которой вы упомянули выше, потому что функция open
имеет обновление состояния и open()
будет вызываться каждый раз, когда приложение выполняет повторную визуализацию, что в конечном итоге приводит к бесконечным повторным визуализациям.
Можете ли вы попробовать переместить AnimatePresence внутри условия, как в моем первом коде.
Ваш первый код работает @irfan çini, но он удаляет анимацию, которую я установил для AppForm
, когда вы нажимаете close
, поэтому я не могу использовать этот метод. { AnimationPresence }
позволяет анимации действовать, даже если компонент удален из DOM
(что происходит, когда вы нажимаете на всплывающее окно).
Однако ваш второй код был в порядке. Спасибо и тебе @Hilory.
Я думаю, вы можете сделать это, хотя эти функции внутри onClick будут перерисованы, но на самом деле они не требуют больших затрат:
import React, { useState, useEffect } from 'react'
import { X } from 'lucide-react'
import { AnimatePresence } from 'framer-motion';
import AppForm from './AppForm';
const AppContent = () => {
const [applicationOpen, setApplicationOpen] = useState(false);
return (
<>
<button
className='apply-btn'
onClick = {() => setApplicationOpen((prev) => !prev)}
>
APPLY HERE
</button>
<AnimatePresence>
{applicationOpen &&
<AppForm applicationOpen = {applicationOpen}
handleClose = {() => setApplicationOpen(false)}/>}
</AnimatePresence>
</>
)
}
export default AppContent
Придерживаясь уже имеющегося у вас подхода, вы можете использовать крючок useCallback
для создания функции, которая не выполняет повторный рендеринг каждый раз при обновлении приложения.
import React, { useState, useCallback } from 'react'
import { X } from 'lucide-react'
import { AnimatePresence } from 'framer-motion';
import AppForm from './AppForm';
const AppContent = () => {
const [ applicationOpen, setApplicationOpen ] = useState(false);
const close = useCallback(() => setApplicationOpen(false),[]);
const open = useCallback(() => setApplicationOpen(true), []);
return (
<>
<button
className='apply-btn'
onClick = {applicationOpen ? close : open}
>
APPLY HERE
</button>
<AnimatePresence>
{applicationOpen &&
<AppForm
applicationOpen = {applicationOpen}
handleClose = {close}
/>
}
</AnimatePresence>
</>
)
}
export default AppContent
Вы не можете использовать функции close и open вне useEffect, поскольку они объявлены в области функции, а не в глобальной области. Чтобы сделать их доступными глобально в рамках основной функции, вам необходимо объявить открытые и закрытые в глобальной области видимости. Вот почему первая реализация работает.
import React, { useState, useEffect } from 'react'
import { X } from 'lucide-react'
import { AnimatePresence } from 'framer-motion';
import AppForm from './AppForm';
const AppContent = () => {
const [ applicationOpen, setApplicationOpen ] = useState(false);
const close = () => setApplicationOpen(false);
const open = () => setApplicationOpen(true);
return (
<>
<button
className='apply-btn'
onClick = {() => applicationOpen ? close() : open()}
>
APPLY HERE
</button>
<AnimatePresence>
{applicationOpen && <AppForm applicationOpen = {applicationOpen} handleClose = {close}/>}
</AnimatePresence>
</>
)
}
export default AppContent
И вторая реализация не работает.
Хук useCallback в React запоминает функции, чтобы предотвратить их воссоздание при каждом рендеринге, сокращая ненужные повторные рендеринги, когда зависимости не изменились.
import React, { useState, useCallback } from "react";
import { X } from "lucide-react";
import { AnimatePresence } from "framer-motion";
import AppForm from "./AppForm";
const AppContent = () => {
const [applicationOpen, setApplicationOpen] = useState(false);
const toggleAppication = useCallback(() => {
setApplicationOpen((prev) => !prev);
}, []);
return (
<>
<button className = "apply-btn" onClick = {toggleAppication}>
APPLY HERE
</button>
<AnimatePresence>
{applicationOpen && (
<AppForm applicationOpen = {applicationOpen} handleClose = {close} />
)}
</AnimatePresence>
</>
);
};
export default AppContent;
Спасибо @Tejas Faldu. Этот метод я тоже опробовал и работает. Однако вам также придется изменить значение handleClose
на {toggleApplication}
.
close
иopen
относятся к вашей функции обратного вызоваuseEffect
, к ним нельзя получить доступ за пределами этой функции. Переопределениеopen
/close
при каждом рендеринге не сильно повредит производительности ваших программ, я бы предложил оставить все как есть или изучить определение ваших функций в редукторе или вне вашего компонента, если вы действительно не хотите переопределить их