Вопрос или проблема
Я работаю над компонентом React, который позволяет пользователям менять тему моего приложения с помощью выпадающего меню DaisyUI. Выбранная тема сохраняется в localStorage
, чтобы сохранять её при обновлении страницы. Однако, когда страница обновляется, выпадающее меню всегда открыто. Я хочу, чтобы оно было закрыто и открывалось только при нажатии на него.
Вот мой код:
import { useEffect, useState } from "react";
function ChangeTheme() {
const \[selectedTheme, setSelectedTheme\] = useState(
localStorage.getItem("selectedTheme") || "default"
);
useEffect(() =\> {
localStorage.setItem("selectedTheme", selectedTheme);
// Применить выбранную тему
document.documentElement.setAttribute("data-theme", selectedTheme);
}, \[selectedTheme\]);
return (
\<div className="dropdown absolute left-0 top-0 m-3"\>
\<div tabIndex={0} role="button" className="btn m-1"\>
Тема
\<svg
width="12px"
height="12px"
className="inline-block h-2 w-2 fill-current opacity-60"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 2048 2048"
\\\>
\<path d="M1799 349l242 241-1017 1017L7 590l242-241 775 775 775-775z"\>\</path\>
\</svg\>
\</div\>
\<ul
tabIndex={0}
className="dropdown-content bg-base-300 rounded-box z-\[1\] w-52 p-2 shadow-2xl"
\\\>
\<li\>
\<input
type="radio"
name="theme-dropdown"
className="theme-controller btn btn-sm btn-block btn-ghost justify-start"
aria-label="Default"
value="default"
checked={selectedTheme === "default"}
onChange={() =\> setSelectedTheme("default")}
/\>
\</li\>
\<li\>
\<input
type="radio"
name="theme-dropdown"
className="theme-controller btn btn-sm btn-block btn-ghost justify-start"
aria-label="Dark"
value="dark"
checked={selectedTheme === "dark"}
onChange={() =\> setSelectedTheme("dark")}
/\>
\</li\>
\<li\>
\<input
type="radio"
name="theme-dropdown"
className="theme-controller btn btn-sm btn-block btn-ghost justify-start"
aria-label="Coffee"
value="coffee"
checked={selectedTheme === "coffee"}
onChange={() =\> setSelectedTheme("coffee")}
/\>
\</li\>
\</ul\>
\</div\>
);
}
export default ChangeTheme;
Ответ или решение
Для того чтобы решить проблему автоматического открытия выпадающего меню при загрузке страницы в компоненте React с использованием DaisyUI, необходимо внести несколько корректировок в ваш код. Давайте разберем этот вопрос детально, а также предложим решения, которые обеспечат правильное поведение выпадающего меню.
Анализ проблемы
Вы сталкиваетесь с ситуацией, когда выпадающее меню для выбора темы всегда открыто после обновления страницы. Это связано с тем, как DaisyUI обрабатывает состояние видимости своих компонентов, если они не считаются интерактивными элементами с предопределенным состоянием. Вам нужно контролировать открытие меню с помощью состояния в вашем компоненте.
Решение
Создадим локальное состояние для управления видимостью выпадающего меню. Также добавим обработчик событий, который будет переключать это состояние при клике на кнопку вызова меню.
Вот переработанный код компонента:
import { useEffect, useState } from "react";
function ChangeTheme() {
const [selectedTheme, setSelectedTheme] = useState(
localStorage.getItem("selectedTheme") || "default"
);
const [isOpen, setIsOpen] = useState(false); // Состояние для управления видимостью меню
useEffect(() => {
localStorage.setItem("selectedTheme", selectedTheme);
document.documentElement.setAttribute("data-theme", selectedTheme);
}, [selectedTheme]);
const toggleDropdown = () => {
setIsOpen(!isOpen); // Переключаем состояние меню
};
const handleThemeChange = (theme) => {
setSelectedTheme(theme);
setIsOpen(false); // Закрываем меню после выбора темы
};
return (
<div className="dropdown absolute left-0 top-0 m-3">
<div
tabIndex={0}
role="button"
className="btn m-1"
onClick={toggleDropdown} // Обработчик клика для открытия/закрытия меню
>
Тема
<svg
width="12px"
height="12px"
className="inline-block h-2 w-2 fill-current opacity-60"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 2048 2048"
>
<path d="M1799 349l242 241-1017 1017L7 590l242-241 775 775 775-775z"/>
</svg>
</div>
{isOpen && ( // Условный рендеринг для выпадающего меню
<ul className="dropdown-content bg-base-300 rounded-box z-[1] w-52 p-2 shadow-2xl">
<li>
<input
type="radio"
name="theme-dropdown"
className="theme-controller btn btn-sm btn-block btn-ghost justify-start"
aria-label="Default"
value="default"
checked={selectedTheme === "default"}
onChange={() => handleThemeChange("default")}
/>
</li>
<li>
<input
type="radio"
name="theme-dropdown"
className="theme-controller btn btn-sm btn-block btn-ghost justify-start"
aria-label="Dark"
value="dark"
checked={selectedTheme === "dark"}
onChange={() => handleThemeChange("dark")}
/>
</li>
<li>
<input
type="radio"
name="theme-dropdown"
className="theme-controller btn btn-sm btn-block btn-ghost justify-start"
aria-label="Coffee"
value="coffee"
checked={selectedTheme === "coffee"}
onChange={() => handleThemeChange("coffee")}
/>
</li>
</ul>
)}
</div>
);
}
export default ChangeTheme;
Объяснение изменений
-
Состояние видимости меню: Мы добавили состояние
isOpen
, которое управляет открытием и закрытием выпадающего меню. -
Обработчик кликов: Функция
toggleDropdown
используется для переключения состояния видимости меню при клике на кнопку. -
Закрытие меню после выбора темы: При выборе темы с помощью функции
handleThemeChange
, мы не только обновляемselectedTheme
, но и закрываем меню. -
Условный рендеринг: Мы добавили условное отображение меню
ul
только в том случае, еслиisOpen
истинно.
Заключение
С помощью указанных изменений ваш компонент будет вести себя корректно, не открывая выпадающее меню автоматически при загрузке страницы. Кроме того, пользователь сможет удобно выбирать тему, а ваша реализация обеспечит хорошую интерактивность. Это решение соответствует современным требованиям разработки на React и позволяет для поддержания чистоты и читаемости кода.