UseEffect для модального всплывающего окна

В настоящее время я пытаюсь включить модальную функцию всплывающего окна, которую мне удалось сделать, и она работает, однако теперь я пытаюсь создать ту же самую функцию внутри хука 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

Может ли кто-нибудь помочь мне, пожалуйста, и указать, что я делаю неправильно? Спасибо.

close и open относятся к вашей функции обратного вызова useEffect, к ним нельзя получить доступ за пределами этой функции. Переопределение open/close при каждом рендеринге не сильно повредит производительности ваших программ, я бы предложил оставить все как есть или изучить определение ваших функций в редукторе или вне вашего компонента, если вы действительно не хотите переопределить их
Nick Parsons 03.08.2024 13:46
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
62
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

С первым кодом, которым вы поделились, проблем нет. Вы делаете 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.

  1. Функция
  2. Массив зависимостей

Всякий раз, когда реквизиты или состояния, которые вы указываете в массиве зависимостей, изменяются, вызывается указанная вами функция. Он также вызывался при запуске. Это когда компонент смонтирован.

Итак, ваша функция внутри 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, чтобы избежать этого. В любом случае, спасибо.

ryanl 03.08.2024 14:08

Это должно быть потому, что вы изначально пытались вызвать функцию close или open непосредственно на кнопке onClick. например onClick = {open()} Это приведет к ошибке, о которой вы упомянули выше, потому что функция open имеет обновление состояния и open() будет вызываться каждый раз, когда приложение выполняет повторную визуализацию, что в конечном итоге приводит к бесконечным повторным визуализациям.

Hilory 03.08.2024 14:13

Можете ли вы попробовать переместить AnimatePresence внутри условия, как в моем первом коде.

irfan çini 03.08.2024 14:30

Ваш первый код работает @irfan çini, но он удаляет анимацию, которую я установил для AppForm, когда вы нажимаете close, поэтому я не могу использовать этот метод. { AnimationPresence } позволяет анимации действовать, даже если компонент удален из DOM (что происходит, когда вы нажимаете на всплывающее окно).

ryanl 03.08.2024 16:01

Однако ваш второй код был в порядке. Спасибо и тебе @Hilory.

ryanl 03.08.2024 16:01

Я думаю, вы можете сделать это, хотя эти функции внутри 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}.

ryanl 05.08.2024 18:17

Другие вопросы по теме