Мой файл макета:
import Menu from "./Menu";
import ButtonMenu from "./ButtonMenu";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang = "en">
<body className = "grid h-screen grid-cols-[repeat(4,min-content)] overflow-x-scroll">
<Menu />
<Pane1 />
<Pane2 />
<Pane3 />
<div className = "w-[100vw]">
<ButtonMenu />
<main>{children}</main>
</div>
</body>
</html>
);
}
Файл моего меню:
"use client";
import { useState } from "react";
export default function Menu() {
const [open, setOpen] = useState(true);
return (
<div
className = {` overflow-x-hidden overflow-y-scroll ${ open ? "w-[5vw]" : "w-[20vw]" }`}
>
<button type = "button" onClick = {() => setOpen(!open)}>
...
</button>
<nav><ul><li></li></ul></nav>
</div>
);
}
Мой файл ButtonMenu:
"use client";
import { useState } from "react";
export default function OpenMenu() {
const [open, setOpen] = useState(true);
return (
<div>
<button type = "button" onClick = {() => setOpen(!open)}>
...
</button>
</div>
);
}
Проблема у меня простая. Когда вы нажимаете на button
(событие onClick), которое находится в файле ButtonMenu
, Menu
не открывается/закрывается и ничего не происходит, ПОЧЕМУ?. Компонент Menu
представляет собой отдельный файл. Файл Menu
и файл ButtonMenu
— это два компонента внутри моего файла Layout
. Почему ButtonMenu
не открывает/закрывает Menu
?
🤔 А знаете ли вы, что...
React Testing Library - это инструмент для тестирования компонентов React.
Если вы хотите изменить что-то внутри компонента Menu
в соответствии с переменной состояния , она должна быть определена внутри него или передана ему как часть его реквизита. open
, который вы создали в ButtonMenu
, не может иметь никакого влияния на Menu
.
Если вы хотите управлять меню из разных компонентов, вы можете использовать контекст . Для этого сначала создайте файл ниже:
// app/MenuContextProvider.tsx
"use client";
import { createContext, useContext, useState } from "react";
const MenuContext = createContext<{ open: boolean; setOpen: Function }>({
open: false,
setOpen: () => {},
});
export default function MenuContextProvider({ children }: { children: React.ReactNode }) {
const [open, setOpen] = useState(true);
return <MenuContext.Provider value = {{ open, setOpen }}>{children}</MenuContext.Provider>;
}
export function useMenuContext() {
return useContext(MenuContext);
}
Измените свой Layout.tsx
на:
import Menu from "./Menu";
import ButtonMenu from "./ButtonMenu";
import MenuContextProvider from "./MenuContextProvider"
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang = "en">
<body className = "grid h-screen grid-cols-[repeat(4,min-content)] overflow-x-scroll">
<MenuContextProvider>
<Menu />
<Pane1 />
<Pane2 />
<Pane3 />
<div className = "w-[100vw]">
<ButtonMenu />
<main>{children}</main>
</div>
</MenuContextProvider>
</body>
</html>
);
}
Компонент Menu.tsx
для:
"use client";
import { useMenuContext } from "./MenuContextProvider"
export default function Menu() {
const {open, setOpen} = useMenuContext();
return (
<div
className = {` overflow-x-hidden overflow-y-scroll ${ open ? "w-[5vw]" : "w-[20vw]" }`}
>
<button type = "button" onClick = {() => setOpen(!open)}>
...
</button>
<nav><ul><li></li></ul></nav>
</div>
);
}
И, наконец, ваш ButtonMenu.tsx
, чтобы:
"use client";
import { useMenuContext } from "./MenuContextProvider"
export default function OpenMenu() {
const {open, setOpen} = useMenuContext();
return (
<div>
<button type = "button" onClick = {() => setOpen(!open)}>
...
</button>
</div>
);
}