javascript - 使用 useState() 为 Nav 中的活动链接共享组件状态
问题描述
我正在尝试学习对框架的反应和相当新的知识。我正在尝试使用具有响应性的 material-ui 创建一个简单的导航栏组件(将显示中型设备及以上设备上的所有链接,并在小型设备上打开一个侧抽屉)。我根据自己的喜好进行了大部分设置,但是,我目前遇到的问题是根据我所在的页面获取和设置活动链接。
它似乎在中型设备及更高版本上正常工作,但是当转换到较小的设备时,链接不会正确更新,因为它会保留中型屏幕集的活动链接,同时更新侧抽屉活动链接。
导航栏.js
const Navbar = () => {
const classes = useStyles();
const pathname = window.location.pathname;
const path = pathname === '' ? '' : pathname.substr(1);
const [selectedItem, setSelectedItem] = useState(path);
const handleItemClick = (event, selected) => {
setSelectedItem(selected);
console.log(selectedItem);
};
return (
<>
<HideNavOnScroll>
<AppBar position="fixed">
<Toolbar component="nav" className={classes.navbar}>
<Container maxWidth="lg" className={classes.navbarDisplayFlex}>
<List>
<ListItem
button
component={RouterLink}
to="/"
selected={selectedItem === ''}
onClick={event => handleItemClick(event, '')}
>
<ListItemText className={classes.item} primary="Home" />
</ListItem>
</List>
<Hidden smDown>
<List
component="nav"
aria-labelledby="main navigation"
className={classes.navListDisplayFlex}
>
<ListItem
button
component={RouterLink}
to="/account/login"
selected={selectedItem === 'account/login'}
onClick={event => handleItemClick(event, 'account/login')}
>
<ListItemText className={classes.item} primary="Login" />
</ListItem>
<ListItem
button
component={RouterLink}
to="/account/register"
selected={selectedItem === 'account/register'}
onClick={event => handleItemClick(event, 'account/register')}
>
<ListItemText className={classes.item} primary="Register" />
</ListItem>
</List>
</Hidden>
<Hidden mdUp>
<SideDrawer />
</Hidden>
</Container>
</Toolbar>
</AppBar>
</HideNavOnScroll>
<Toolbar id="scroll-to-top-anchor" />
<ScrollToTop>
<Fab aria-label="Scroll back to top">
<NavigationIcon />
</Fab>
</ScrollToTop>
</>
)
}
SideDrawer.js
const SideDrawer = () => {
const classes = useStyles();
const [state, setState] = useState({ right: false });
const pathname = window.location.pathname;
const path = pathname === "" ? "" : pathname.substr(1);
const [selectedItem, setSelectedItem] = useState(path);
const handleItemClick = (event, selected) => {
setSelectedItem(selected);
console.log(selectedItem);
};
const toggleDrawer = (anchor, open) => (event) => {
if (
event &&
event.type === "keydown" &&
(event.key === "Tab" || event.key === "Shift")
) {
return;
}
setState({ ...state, [anchor]: open });
};
const drawerList = (anchor) => (
<div
className={classes.list}
role="presentation"
onClick={toggleDrawer(anchor, false)}
onKeyDown={toggleDrawer(anchor, false)}
>
<List component="nav">
<ListItem
button
component={RouterLink}
to="/account/login"
selected={selectedItem === "account/login"}
onClick={(event) => handleItemClick(event, "account/login")}
>
<ListItemText className={classes.item} primary="Login" />
</ListItem>
<ListItem
button
component={RouterLink}
to="/account/login"
selected={selectedItem === "account/register"}
onClick={(event) => handleItemClick(event, "account/register")}
>
<ListItemText className={classes.item} primary="Register" />
</ListItem>
</List>
</div>
);
return (
<React.Fragment>
<IconButton
edge="start"
aria-label="Menu"
onClick={toggleDrawer("right", true)}
>
<Menu fontSize="large" style={{ color: "white" }} />
</IconButton>
<Drawer
anchor="right"
open={state.right}
onClose={toggleDrawer("right", false)}
>
{drawerList("right")}
</Drawer>
</React.Fragment>
);
};
代码沙箱- https://codesandbox.io/s/async-water-yx90j
我在 SO 上遇到了这个问题:是否可以使用 React 中的 useState() 钩子在组件之间共享状态?,这表明我需要将状态提升到一个共同的祖先组件,但我不太明白如何在我的情况下应用它。
解决方案
我建议暂时搁置您的代码并为这种提升状态理解做一个操场。提升状态是在不相关的组件之间共享状态的基本策略。基本上在某个共同的祖先是 state 和 setState 将存在的地方。在那里你可以作为道具传递给它的孩子:
const Parent = () => {
const [name, setName] = useState('joe')
return (
<>
<h1>Parent Component</h1>
<p>Child Name is {name}</p>
<FirstChild name={name} setName={setName} />
<SecondChild name={name} setName={setName} />
</>
)
}
const FirstChild = ({name, setName}) => {
return (
<>
<h2>First Child Component</h2>
<p>Are you sure child is {name}?</p>
<button onClick={() => setName('Mary')}>My Name is Mary</button>
</>
)
}
const SecondChild = ({name, setName}) => {
return (
<>
<h2>Second Child Component</h2>
<p>Are you sure child is {name}?</p>
<button onClick={() => setName('Joe')}>My Name is Joe</button>
</>
)
}
如您所见,只有一种状态,一种真理来源。状态位于Parent
并向下传递到它的children
. 现在,如果您需要将您的州定位在某个遥远的 GreatGrandParent,有时会很麻烦。你必须把每个孩子都传下去,直到到达那里,这很烦人。如果你发现自己处于这种情况,你可以使用React Context API。而且,对于最复杂的状态管理,还有redux 之类的解决方案。
推荐阅读
- c# - 正则表达式:C# 从 javascript 部分中提取值
- excel - 选择包含文本的第一行中的最后一列,然后转到下一行并执行相同操作
- python - 一个函数中的两个列表,在 python 中有 n 个列表,执行最少
- c# - 在 Asp.Net Core 3.3 中从 appSettings.json 访问 ConnectionString 时出现异常
- r - 如何使用 R 在 n 维中应用此代码?
- python - Tkinter - 如何更改菜单栏小部件中的分隔符样式?
- excel - 带有高级过滤器的 Excel VBA“错误:Excel 资源不足”
- bash - 获取 bash_profile 不会删除注释的别名/函数
- jquery - 如何检查最后一个 TR 的最后一个 TD 是否包含一个空的选择字段和三个空的输入字段?
- android - 如何在 React Native 上制作软波纹动画?