[英]React setting initial state based on one of child components parameters
I am making an app with menu bar and sliding selected menu item indicator.我正在制作一个带有菜单栏和滑动选定菜单项指示器的应用程序。 It kind of works, but I have several problems:
它有点工作,但我有几个问题:
widthOffset
, leftOffset
and color
) is hardcoded, but I need it to always follow the active NavLink
, so when I open my app - the indicator is immediately in the right place at selected NavLink
(if you select anything but Home
NavLink
and reload app, you will be at last page, but indicator resets to hardcoded state).widthOffset
, leftOffset
和color
)是硬编码的,但我需要它始终遵循活动的NavLink
,所以当我打开我的应用程序时 - 指示器立即在所选NavLink
的正确位置(如果你 select 除了Home
NavLink
并重新加载应用程序,您将在最后一页,但指示器重置为硬编码状态)。activeStyle
from e.target
, so colors are also weirdly hardcoded with this double menuItems.*NavLink name*.color
in each NavLink
.e.target
获取activeStyle
值的方法,因此 colors 在每个NavLink
中也用这个双menuItems.*NavLink name*.color
进行了奇怪的硬编码。 What is the best way to implement this?实现这一点的最佳方法是什么?
full codesandbox: https://codesandbox.io/s/ecstatic-moon-mqbnk完整的代码框: https://codesandbox.io/s/ecstatic-moon-mqbnk
code:代码:
import React, { useState } from "react";
import { NavLink } from "react-router-dom";
const Navigation = () => {
const menuItems = {
Home: {
color: 'orange',
},
About: {
color: 'green',
},
Contacts: {
color: 'rebeccapurple',
},
}
const [offsetWidth, setWidth] = useState(84);
const [offsetLeft, setLeft] = useState(26);
const [color, setColor] = useState("orange");
function switchMenu(e, color) {
setWidth(e.target.offsetWidth);
setLeft(e.target.offsetLeft);
setColor(color);
}
return (
<nav className="nav">
<NavLink
refs="Home"
exact
className="nav-item"
activeClassName="nav-item is active"
activeStyle={{ color: menuItems.Home.color }}
to="/"
onClick={(e) => switchMenu(e, menuItems.Home.color)}
>
Home
</NavLink>
<NavLink
refs="About"
exact
className="nav-item"
activeClassName="nav-item is active"
activeStyle={{ color: menuItems.About.color }}
to="/about"
onClick={(e) => switchMenu(e, menuItems.About.color)}
>
About
</NavLink>
<NavLink
refs="Contacts"
exact
className="nav-item"
activeClassName="nav-item is active"
activeStyle={{ color: menuItems.Contacts.color }}
to="/contact"
onClick={(e) => switchMenu(e, menuItems.Contacts.color)}
>
Contacts
</NavLink>
<span
style={{
position: "absolute",
left: `${offsetLeft}px`,
width: `${offsetWidth}px`,
backgroundColor: `${color}`,
bottom: "0px",
height: "5px",
transition: ".4s",
zIndex: "1",
borderRadius: "8px 8px 0 0",
}}
></span>
</nav>
);
};
export default Navigation;
UPD:升级版:
I managed o solve some problems, using isActive
of NavLink
, now the indicator is always in place, but still have a lil bit of trouble:我设法解决了一些问题,使用
NavLink
的isActive
,现在指示器总是在适当的位置,但仍然有点麻烦:
onClick
and this destroys the state and rerendering power of React.onClick
,这会破坏 state 和 React 的重新渲染能力。 I did not find a way to toggle useEffect
to rerender the indicator when I change selected link.useEffect
以重新呈现指示器。 Also when I try not to directly change the state onClick
, but to run setCurrentPage()
it works 1/2 times, cause onClick
happens fatser, than className change.onClick
,但运行setCurrentPage()
它工作 1/2 次,导致onClick
发生更胖,而不是类。Ctrl + F5
and the fonts, etc. jump - the indicator renders a little bit not in it's place.Ctrl + F5
并且 fonts 等会跳转 - 指示器会呈现一点点不在它的位置。 Would be nice if I could render it after all is settled. updated codesandbox: https://codesandbox.io/s/strange-shadow-5jo68更新的代码框: https://codesandbox.io/s/strange-shadow-5jo68
updated Navigattion.js code:更新了 Navigattion.js 代码:
import React, { useState, useRef, useEffect } from "react";
import { NavLink } from "react-router-dom";
const Navigation = () => {
const [offsetWidth, setWidth] = useState(null);
const [offsetLeft, setLeft] = useState(null);
const [color, setColor] = useState(null);
const Home = useRef(null);
const About = useRef(null);
const Contacts = useRef(null);
const menuItems = {
Home: {
ref: Home,
color: "orange",
},
About: {
ref: About,
color: "green",
},
Contacts: {
ref: Contacts,
color: "rebeccapurple",
},
};
function changeIndicator(e, color) {
setWidth(e.offsetWidth);
setLeft(e.offsetLeft);
setColor(color);
}
function setCurrentPage() {
Object.keys(menuItems).forEach((key) => {
if (
menuItems[key].ref.current.className === "nav-item nav-item is active"
) {
changeIndicator(menuItems[key].ref.current, menuItems[key].color);
}
});
}
useEffect(setCurrentPage);
return (
<nav className="nav">
<NavLink
ref={Home}
isActive={(match) => {
if (!match) {
return false;
}
return true;
}}
exact
className="nav-item"
activeClassName="nav-item is active"
activeStyle={{ color: menuItems.Home.color }}
to="/"
onClick={(e) => changeIndicator(e.target, menuItems.Home.color)}
>
Home
</NavLink>
...
As I said in my comment you can use references to check what is the active link and then set the state正如我在评论中所说,您可以使用参考来检查活动链接是什么,然后设置 state
is-active
is-active
className="nav-item"
activeClassName="is-active"
const homeLink = useRef(null);
const aboutLink = useRef(null);
const contactLink = useRef(null);
useEffect(() => {
if (homeLink.current.className.includes("is-active")) {
setWidth(homeLink.current.offsetWidth);
setLeft(homeLink.current.offsetLeft);
setColor(menuItems.Home.color);
} else if (aboutLink.current.className.includes("is-active")) {
setWidth(aboutLink.current.offsetWidth);
setLeft(aboutLink.current.offsetLeft);
setColor(menuItems.About.color);
} else if (contactLink.current.className.includes("is-active")) {
setWidth(contactLink.current.offsetWidth);
setLeft(contactLink.current.offsetLeft);
setColor(menuItems.Contacts.color);
}
}, []);
....
<NavLink
ref={homeLink}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.