Открывайте и закрывайте мобильное меню навигационной панели с помощью стилизованных компонентов

#javascript #reactjs #styled-components

Вопрос:

Я следую руководству о том, как создать простой веб — сайт с использованием стилизованных компонентов.

Когда веб-сайт находится в режиме мобильного просмотра, меню гамбургера остается открытым и не закрывается при нажатии на символ гамбургера или любой из пунктов навигационного меню. Однако символ гамбургера переключается на этот FaTimes символ.

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

Навигационная панель

 import React, {useState, useEffect} from 'react';
import { FaBars, FaTimes } from 'react-icons/fa';
import { Nav, NavbarContainer, NavLogo, NavIcon, MobileIcon, NavItem, NavMenu, NavLinks,
NavItemBtn, NavBtnLink } from './Navbar.elements';
import {Button } from '../globalstyles';
import osun from '../images/Osun.png';
import { IconContext} from 'react-icons/lib';
import Home from './pages/Home';


const Navbar = () => {
    const [click, setClick, isOpen, setIsOpen] = useState(false);
    const [button, setButton] = useState(true);

const toggle = () => setIsOpen(!isOpen);

const hide = () => setIsOpen(false);

const handleClick = () => setClick(!click);

// const toggleShow = () => {
//     this.setState({show: !this.state.show})
// }
//const toggleShow = () => setClick(!show)

// const toggleShow = () => {
//     if (window.innerwidth <= 960){
//         showMenu(false)
//     } else {
//         showMenu(true)
//     }
// }


const showButton = () => {
    if (window.innerWidth <=960){
        setButton(false)
    } else { 
        setButton(true)
    }
};
const closeMobileMenu = () => setClick(false);

useEffect(() => {
    showButton();
    //toggleShow()
}, []);

window.addEventListener('resize', showButton);
//window.addEventListener('resize', toggleShow);
    return (
        <>
        <IconContext.Provider value={{color: "#fff"}}>
        <Nav>
            <NavbarContainer>
                <NavLogo to ="/">
                    <NavIcon />
                    Osun Swap
                </NavLogo>
                <MobileIcon onClick={handleClick} onBlur={hide} >
                    {click ? < FaTimes/> : <FaBars/>}
                    </MobileIcon>
                <NavMenu onClick={handleClick} click ={click}>
                    <NavItem>
                        <NavLinks to = '/' onClick={closeMobileMenu}>
                            Home
                        </NavLinks>
                    </NavItem>
                    <NavItem>
                        <NavLinks to = '/services' onClick={closeMobileMenu}>
                            Services
                        </NavLinks>
                    </NavItem>
                    <NavItem>
                        <NavLinks to = '/AboutUs' onClick={closeMobileMenu}>
                            About us
                        </NavLinks>
                    </NavItem>
                    <NavItemBtn>
                        {button ? (
                            <NavBtnLink to ='/sign-up'>
                                <Button primary> Connect Wallet </Button>
                            </NavBtnLink>
                        ) : (
                            <NavBtnLink to='/sign-up'>
                                <Button onClick={closeMobileMenu} fontBig primary>
                                    Connect Wallet
                                </Button>
                            </NavBtnLink>
                        )}
                    </NavItemBtn>
                </NavMenu>     
            </NavbarContainer>
        </Nav>
        </IconContext.Provider>
        </>
    )
}

export default Navbar;
 

Навигационная панель.элементы

 import styled from 'styled-components';
import { Link } from 'react-router-dom';
import osun from '../images/Osun.png';
import { Container } from '../globalstyles';

export const Nav = styled.nav`
background : #101522;//#282c34;//rgb(35, 31,32);//; //rgb(10, 10, 10);
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2rem;
position: sticky;
top:0;
z-index:999;
`;

export const NavbarContainer = styled(Container)`
display: flex;
justify-content:space-between;
height: 80px;

${Container}
`;

export const NavLogo = styled(Link)`
color: #ffff;
justify-self: flex-start;
cursor: pointer;
font-size: 2rem;
display: flex;
align-items: center;
`;
export const NavIcon = styled.div`
background-image: url(${osun});
margin-right: 0.5rem;

`;
export const MobileIcon = styled.div`

    display: none;

    @media screen and (max-width: 960px){
        display:block;
        position: absolute;
        top: 0;
        right:0 ;
        transform: translate(-100%, 60%);
        font-size: 1.8rem;
        cursor: pointer;
    }
`;

export const NavMenu = styled.ul`
display: flex;
align-items: center;
list-style: none;
//text-decoration: none;
text-align: center;
/* display: flex;
        flex-direction: column;
        width: 100px;
        height: 500px;
        top: 80px;
        left: -100%;
        opacity:1;
        transition: all 0.5s ease; */

    @media screen and (max-width: 960px) {
        display: flex;
        flex-direction: column;
        width: 100%;
        //list-style: none;
        height: 90vh;
        top: 80px;
        //right: -100%;
        right: ${({click}) => (click ? 0 : '-100%')};
        opacity:1;
        //transform: ${({open}) => open ? 'translateX(0)' : 'translateX(100%)'};
        transition: all 0.5s ease;
        background: #101522; //rgb(35, 31,32);//
    }
`;

export const NavItem = styled.li`
height: 80px;
border-bottom: 2px solid transparent;

@media screen and (max-width: 960px){
    //visibility: hidden;
   // display: block;
    position: relative;
    width: 100%;
    //top:0;
    //right:0;
    //transform: translate(-100%, 60%);
    //font-size:1.8rem;
    //cursor: pointer;
}

amp;:hover {
    border-bottom: 2px solid #4b59f7;
}
`;

export const NavLinks = styled(Link)`
color: #fff;
display:flex;
align-items: center;
text-decoration: none;
padding:0.5rem 1rem;
height: 100%;

@media screen and (max-width: 960px){
    text-align: center;
    padding: 2rem;
    width: 100%;
    display: table;

    amp;:hover {
        color:#4b59f7;
        transition: all 0.3s ease;
    }
}
`;

export const NavItemBtn = styled.li`
@media screen and (max-width: 960){
    display:flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    height: 120px
}

`;

export const NavBtnLink= styled(Link)`
    display: flex;
    justify-content:center;
    align-items: center;
    text-decoration: none;
    padding: 8px 16px;
    height: 100%;
    width: 100%;
    border: none;
    outline: none;

`;
 

Ответ №1:

Я попытался воспроизвести вашу проблему и столкнулся с ошибками в вашем примере кода, которые могут быть причиной вашей проблемы. В частности:

 const [click, setClick, isOpen, setIsOpen] = useState(false);
 

не является допустимой настройкой для useState. Попробуйте разделить это на два отдельных вызова useState, например:

 const [click, setClick] = useState(false);
const [isOpen, setIsOpen] = useState(false);
 

Как и в исходном примере, моя среда IDE немедленно пометила эту строку, а также сообщила мне, что isOpen ни к чему не был инициализирован, что вызвало серьезные ошибки, когда я попытался нажать кнопку / размыть ее.

Комментарии:

1. Я просто попытался разделить оператор на два отдельных вызова useState, как вы предлагали, и я не вижу никаких изменений. По какой-то причине моя IDE не отметила эту строку.

2. Если вы регистрируете или отлаживаете обработчики в консоли, что вам сообщает консоль? Какие-либо сообщения об ошибках, или, может быть, они попадают в оба обработчика в странном порядке? Что произойдет, если вы удалите событие размытия и просто сосредоточитесь на событии щелчка?

3. Код компилируется как есть, и я не получаю никаких ошибок. Как я могу приступить к отладке обработчика? Удаление события onBlur не изменяет никаких функциональных возможностей.

4. Если бы это был я, я бы добавил журналы консоли в каждый из обработчиков, показывая значение и какой обработчик был вызван, а затем проверил журналы по щелчку мыши, чтобы увидеть, были ли значения такими, как я ожидал. Взглянув на это еще раз, я подозреваю, что событие handle вызывается дважды, один раз из MobileIcon и один раз из NavIcon, что означало бы, что значение isOpen меняется дважды, возвращаясь к исходному значению. Может быть, попробовать удалить один из них?