ReactJS - 渲染器组件
ReactJS - Rerender component
我正在尝试在 ReactJS 中创建一个菜单,它有一个带图标的边栏和一个 BurgerMenu,我在其中显示与图标匹配的标题。当 select 从 SideBar 或 BurgerMenu 编辑一个菜单项时,它会改变颜色。如果我 select 汉堡菜单中的一个项目,一切正常,但如果我 select 它来自侧边栏,那么在汉堡菜单中,前一个项目保持彩色。汉堡菜单中的项目似乎没有重新渲染,我找不到解决方案。
这是代码:
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">
×
</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
在 BurgerSideNav 组件中,您在构造函数中设置了状态
活动路径:this.props.activePath
但是当 StyledSideNav 组件中的状态发生变化时,您不会再次设置状态,要再次设置状态,请实施 componentWillReceiveProps
例如:
componentWillReceiveProps(nextProps) {
if (this.props.activePath !== nextProps.activePath) {
this.setState({
activePath: nextProps.activePath
})
}
}
如果我对问题的理解正确,如果你想重新渲染,你可以将 activePath
作为 key
的一部分传递,以轻松强制重新渲染:
return (
<NavItem
path={item.path}
name={item.name}
css={item.css}
onItemClick={this.onItemClick}
active={item.path === activePath}
key={`${item.key}-${activePath}`}
/>
);
需要注意的一件事是,您可能只需要在父组件 (SideNav) 中定义 activePath
,如果您不希望两者都设置样式,则不需要在两者中定义,因此为什么两者都保留 'enabled'.
此外,您的项目不会改变,因此它们在其他地方应该保持不变,而不是成为您所在州的一部分。也许在常量文件中:
// PathContants.js
export default PathConstants = [
{
id: 1,
path: '/home',
},
..
];
如果路径始终是唯一的,您可以只使用路径本身作为键 key={item.path}
,因为键实际上是一个字符串。无需存储密钥本身。
我正在尝试在 ReactJS 中创建一个菜单,它有一个带图标的边栏和一个 BurgerMenu,我在其中显示与图标匹配的标题。当 select 从 SideBar 或 BurgerMenu 编辑一个菜单项时,它会改变颜色。如果我 select 汉堡菜单中的一个项目,一切正常,但如果我 select 它来自侧边栏,那么在汉堡菜单中,前一个项目保持彩色。汉堡菜单中的项目似乎没有重新渲染,我找不到解决方案。 这是代码:
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">
×
</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
在 BurgerSideNav 组件中,您在构造函数中设置了状态
活动路径:this.props.activePath
但是当 StyledSideNav 组件中的状态发生变化时,您不会再次设置状态,要再次设置状态,请实施 componentWillReceiveProps
例如:
componentWillReceiveProps(nextProps) {
if (this.props.activePath !== nextProps.activePath) {
this.setState({
activePath: nextProps.activePath
})
}
}
如果我对问题的理解正确,如果你想重新渲染,你可以将 activePath
作为 key
的一部分传递,以轻松强制重新渲染:
return (
<NavItem
path={item.path}
name={item.name}
css={item.css}
onItemClick={this.onItemClick}
active={item.path === activePath}
key={`${item.key}-${activePath}`}
/>
);
需要注意的一件事是,您可能只需要在父组件 (SideNav) 中定义 activePath
,如果您不希望两者都设置样式,则不需要在两者中定义,因此为什么两者都保留 'enabled'.
此外,您的项目不会改变,因此它们在其他地方应该保持不变,而不是成为您所在州的一部分。也许在常量文件中:
// PathContants.js
export default PathConstants = [
{
id: 1,
path: '/home',
},
..
];
如果路径始终是唯一的,您可以只使用路径本身作为键 key={item.path}
,因为键实际上是一个字符串。无需存储密钥本身。