ReactJS - компонент рендеринга - PullRequest
0 голосов
/ 08 марта 2020

Я пытаюсь создать меню в ReactJS с боковой панелью с иконками, а также с BurgerMenu, в котором я отображаю заголовки, соответствующие иконкам. При выборе пункта меню на боковой панели или в BurgerMenu он меняет свой цвет. Если я выбираю элемент в меню бургера, все работает нормально, но если я выбираю его на боковой панели, то в меню бургера предыдущий элемент остается цветным. Кажется, что элементы в меню гамбургера не отображаются, и я не могу найти решение этой проблемы. Вот код:

import React from 'react';

import styled from "styled-components";
import NavItem from "./NavItem";
import BurgerSideNav from "./burger-nav/BurgerSideNav";

/* This defines the actual bar going down the screen */
const StyledSideNav = styled.div`
  position: fixed;     /* Fixed Sidebar (stay in place on scroll and position relative to viewport) */
  height: 100%;
  width: 75px;     /* Set the width of the sidebar */
  z-index: 1;      /* Stay on top of everything */
  top: 3.4em;      /* Stay at the top */
  background-color: #222; /* Black */
  overflow-x: hidden;     /* Disable horizontal scroll */
  padding-top: 10px;
`;

class SideNav extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            activePath: this.props.activePath,
            items: [
                {
                    path: '/', /* path is used as id to check which NavItem is active basically */
                    name: 'Home',
                    css: 'fa fa-fw fa-home',
                    key: 1 /* Key is required, else console throws error. Does this please you Mr. Browser?! */
                },
                {
                    path: '/news',
                    name: 'News',
                    css: 'fas fa-newspaper',
                    key: 2
                },
                {
                    path: '/info',
                    name: 'Info',
                    css: 'fas fa-info',
                    key: 3
                },
                {
                    path: '/profile',
                    name: 'Profile',
                    css: 'fas fa-id-card',
                    key: 4
                },
                {
                    path: '/coordinator',
                    name: 'Coordinator',
                    css: 'fas fa-user-tie',
                    key: 5
                },
                {
                    path: '/contact',
                    name: 'Contact',
                    css: 'fas fa-address-book',
                    key: 6
                },
            ]
        }
    }

    onItemClick = (path) => {
        this.setState({activePath: path}); /* Sets activePath which causes rerender which causes CSS to change */
    };

    render() {
        const { items, activePath } = this.state;
        return (
            <div>
                <StyledSideNav>
                    <BurgerSideNav
                        activePath = {activePath}
                        onItemClick={this.onItemClick}
                    />
                    {
                        /* items = just array AND map() loops thru that array AND item is param of that loop */
                        items.map((item) => {
                            /* Return however many NavItems in array to be rendered */
                            return (
                                <NavItem
                                    path={item.path}
                                    name={item.name}
                                    css={item.css}
                                    onItemClick={this.onItemClick} /* Simply passed an entire function to onClick prop */
                                    active={item.path === activePath}
                                    key={item.key}
                                />
                            )
                        })
                    }
                </StyledSideNav>
            </div>
        );
    }
}

export default SideNav
import React from "react"
import "../sideNav.css"
import BurgerNavItem from "./BurgerNavItem";

class BurgerSideNav extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            showNav: false,
            activePath: this.props.activePath,
            items: [
                {
                    path: '/',
                    name: 'Acasa',
                    css: 'fa fa-fw fa-home',
                    key: 1
                },
                {
                    path: '/news',
                    name: 'Noutati',
                    css: 'fas fa-newspaper',
                    key: 2
                },
                {
                    path: '/info',
                    name: 'Despre lucrare',
                    css: 'fas fa-info',
                    key: 3
                },
                {
                    path: '/profile',
                    name: 'Profil student',
                    css: 'fas fa-id-card',
                    key: 4
                },
                {
                    path: '/coordinator',
                    name: 'Coordonator',
                    css: 'fas fa-user-tie',
                    key: 5
                },
                {
                    path: '/contact',
                    name: 'Contact',
                    css: 'fas fa-address-book',
                    key: 6
                },
            ]
        };
    }

    openNavClick = e => {
        e.preventDefault();
        this.openNav()
    };

    closeNavClick = e => {
        e.preventDefault();
        this.closeNav()
    };

    openNav = () => {
        this.setState({
            showNav: true
        });

        document.addEventListener("keydown", this.handleEscKey)
    };

    closeNav = () => {
        this.setState({
            showNav: false
        });

        document.removeEventListener("keydown", this.handleEscKey)
    };

    handleEscKey = e => {
        if (e.key === "Escape") {
            this.closeNav()
        }
    };

    onItemClick = (path) => {
        const {onItemClick} = this.props;
        this.setState({ activePath: path });
        onItemClick(path);
    };

    render() {
        const { items, activePath, showNav } = this.state;
        let navCoverStyle = { width: showNav ? "100%" : "0" }
        let sideNavStyle = { width: showNav ? "250px" : "0" }

        return (
            <React.Fragment>
                <span onClick={this.openNavClick}>
                    <i className="fas fa-bars open-nav"/>
                </span>
                <div
                    onClick={this.navCoverClick}
                    class="nav-cover"
                    style={navCoverStyle}
                />
                <div name="side-nav" class="side-nav" style={sideNavStyle}>
                    <a href="#" onClick={this.closeNavClick} class="close-nav">
                        &times;
                    </a>
                    {
                        items.map((item) => {
                            return (
                                <BurgerNavItem
                                    path={item.path}
                                    name={item.name}
                                    css={item.css}
                                    onItemClick={this.onItemClick}
                                    active={item.path === activePath}
                                    key={item.key}/>
                            )
                        })
                    }
                </div>
            })
            </React.Fragment>
        )
    }
}

export default BurgerSideNav

Ответы [ 2 ]

1 голос
/ 08 марта 2020

Если я правильно понимаю вопрос, если вы хотите выполнить повторную визуализацию, вы можете передать activePath как часть key, чтобы легко вызвать повторную визуализацию:

return (
    <NavItem
        path={item.path}
        name={item.name}
        css={item.css}
        onItemClick={this.onItemClick}                                   
        active={item.path === activePath}
        key={`${item.key}-${activePath}`}
    />
);

One Следует отметить, что вам, вероятно, нужно только activePath, определенный в родительском компоненте (SideNav), а не в обоих, если вы не хотите, чтобы оба стиля были стилизованы, поэтому оба остаются «включенными».

Также Ваши предметы не изменятся, поэтому они должны быть постоянными где-то еще, а не быть частью вашего состояния. Может быть, в файле констант:

// PathContants.js

export default PathConstants = [
  {
    id: 1,
    path: '/home',
  },
  ..
];

Если пути всегда уникальны, вы можете просто использовать сам путь в качестве ключа key={item.path}, поскольку ключ на самом деле является строкой. Не нужно хранить сам ключ.

0 голосов
/ 08 марта 2020

в компоненте BurgerSideNav вы установили состояние в функции конструктора, говоря:

activePath: this.props.activePath

, но когда состояние изменяется в компоненте StyledSideNav, вы не устанавливаете состояние снова, чтобы установить состояние снова, реализуйте componentWillReceiveProps

например:

componentWillReceiveProps(nextProps) {
  if (this.props.activePath !== nextProps.activePath) {
     this.setState({
       activePath: nextProps.activePath
     })
  }
}
...