React - 从子级访问父级的状态,无需嵌套函数
你好,
我今天第一次来找你,因为我还没有找到解决我的问题的方法。
我已经使用 React 几个星期了,不要对我的代码质量太残酷
Hello,
I am coming to you today for the first time because I have not found a solution to my problem.
I have been using react for a few weeks, Don't be too cruel about the quality of my code ????.
Problem :
I am looking to access the state of a parent from their children.So I want to be able to access the setHeight function and the height variable for example from a child component.
Please note :
However, to keep some flexibility, I don't want to have any Components inside our.
I looked at redux to be able to do this, but the problem is that the data is global so creating multiple dropdowns would not be possible.
(Unless I didn't understand too much, redux is quite complex)
Diagram :
I have created a diagram to explain it a little better.,
I'd like the children of DropdownMenu to be able to access the state of the latter, Also, the different Dropdowns must have their own state independently.
So ideally I want to keep the same structure as find very flexible, and the possibility to create several dropdown.
Code :
I Share my four components :
export default function Navbar () {
return (
<nav className={styles.navbar}>
<ul className={styles.navbarNav}>
<NavItem icon={<NotificationsIcon />} />
<NavItem icon={<AccessTimeFilledIcon />} />
<NavItem icon={<FileOpenIcon />}>
<DropdownMenu>
<DropdownSubMenu menuName="Home">
<DropdownItem>My Profile</DropdownItem>
<DropdownItem leftIcon={<AccessTimeFilledIcon />} rightIcon={<ChevronRightIcon />} goToMenu="pages">Pages</DropdownItem>
<DropdownItem>IDK</DropdownItem>
<DropdownItem>Test</DropdownItem>
</DropdownSubMenu>
<DropdownSubMenu menuName="pages">
<DropdownItem>Pages</DropdownItem>
<DropdownItem leftIcon={<AccessTimeFilledIcon />} rightIcon={<ChevronRightIcon />} goToMenu="home">Home</DropdownItem>
</DropdownSubMenu>
</DropdownMenu>
<DropdownMenu>
<DropdownSubMenu menuName="config">
<DropdownItem>Foo</DropdownItem>
<DropdownItem leftIcon={<AccessTimeFilledIcon />} rightIcon={<ChevronRightIcon />} goToMenu="theme">Configuration</DropdownItem>
<DropdownItem>Bar</DropdownItem>
<DropdownItem>Baz</DropdownItem>
</DropdownSubMenu>
<DropdownSubMenu menuName="theme">
<DropdownItem>Hi StackOverflow</DropdownItem>
<DropdownItem leftIcon={<AccessTimeFilledIcon />} rightIcon={<ChevronRightIcon />} goToMenu="config">Theme</DropdownItem>
</DropdownSubMenu>
</DropdownMenu>
</NavItem>
</ul>
</nav>
);
};
type Props = {
children?: React.ReactNode | React.ReactNode[];
leftIcon?: React.ReactNode | JSX.Element | Array<React.ReactNode | JSX.Element>;
rightIcon?: React.ReactNode | JSX.Element | Array<React.ReactNode | JSX.Element>;
goToMenu?: string;
goBack?: boolean;
OnClick?: () => void;
};
export default function DropdownItem({ children, leftIcon, rightIcon, goToMenu, goBack, OnClick }: Props) {
const handleClick = OnClick === undefined ? () => { } : OnClick;
return (
<a className={styles.menuItem} onClick={() => {
goToMenu && setActiveMenu(goToMenu);
setDirection(goBack ? 'menu-right' : 'menu-left');
handleClick();
}}>
<span className={styles.iconButton}>{leftIcon}</span>
{children}
<span className={styles.iconRight}>{rightIcon}</span>
</a>
);
}
type Props = {
menuName: string;
children: React.ReactNode | React.ReactNode[];
}
enum Direction {
LEFT = 'menu-left',
RIGHT = 'menu-right'
}
export default function DropdownSubMenu (props: Props) {
const [direction, setDirection] = useState<Direction>(Direction.LEFT);
const calcHeight = (element: HTMLElement) => {
if (element) setMenuHeight(element.offsetHeight);
};
return (
<CSSTransition in={activeMenu === props.menuName} unmountOnExit timeout={500} classNames={direction} onEnter={calcHeight}>
<div className={styles.menu}>
{props.children}
</div>
</CSSTransition>
);
}
type Props = {
children: React.ReactNode | React.ReactNode[];
}
export default function DropdownMenu (props: Props) {
const [activeMenu, setActiveMenu] = useState<string>('home');
const [menuHeight, setMenuHeight] = useState<number | null>(null);
const dropdownRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const child = dropdownRef.current?.firstChild as HTMLElement;
const height = getHeight(child);
if (height)
setMenuHeight(height);
}, []);
return (
<div className={styles.dropdown} style={{ height: `calc(${menuHeight}px + 2rem)` }} ref={dropdownRef}>
{props.children}
</div>
);
}
Conclusion :
More concretely I don't know what to put instead :
In DropdownSubMenu to set the menu height (setMenuHeight), and gets the active menu (activeMenu).
In DropdownItem, set the active menu, (setActiveMenu) and set the direction of the CSS animation (setDirection).
Source :
My code is adapted from these sources, But I want to make this code more professional, flexible and polymorphic :
https://github.com/fireship-io/229-multi-level-dropdown
I've been tried :
I tried to look at Redux, but I understood that it was only state global.
So it doesn't allow to define a different context for each component.
I tried to look at React 18, without success.
I have searched the StackOverflow posts, I have searched the state retrieval from the parents.
The use of components inside a component solves in effect the problem but we lose all the flexibility.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
有多种方法可以从子状态访问父状态。
将状态作为 props 传递
首选方法是将状态和/或更改函数传递给子级。
示例:
演示: https://jsfiddle.net/47s28ge5/1/
使用 React Context
第一个当子级嵌套很深并且您不想沿着组件树携带状态时,方法会变得复杂。
然后,您可以使用上下文在多个子级之间共享状态。
演示:https://jsfiddle.net/dho0tmc2/3/
使用减速器
如果您的代码得到更复杂的是,您可能会考虑使用存储在组件之间共享全局状态。
您可以查看流行的选项,例如:
There are multiple ways to access a parent state from its children.
Pass the state as props
The preferred way is to pass the state and/or the change function to the children.
Example :
Demo: https://jsfiddle.net/47s28ge5/1/
Use React Context
The first method becomes complicated when the children are deeply nested and you don't want to carry the state along the component tree.
You can then share a state across multiple children by using context.
Demo: https://jsfiddle.net/dho0tmc2/3/
Using a reducer
If your code gets even more complicated, you might consider using a store to share a global state across your components.
You can take a look at popular options such as:
我可以说欢迎此时此刻做出反应,我为你感到高兴
好的,我可以理解你的问题是什么。
但没有问题,这个错误是由于你的经验不足造成的。
据我了解,您想要单击下拉菜单并将其打开。
这里我们有嵌套的下拉菜单。
我想这就是你的答案:
您应该在每个下拉列表中声明一个状态,而不是在父级中声明状态。
I can say welcome to react in this moment and i glad for you
OK, i could understand what is your problem.
but there isn't problem and this bug cause from your low experience.
As i understand you want to click on a dropdown and open it.
and here we have nested dropdown.
I think it's your answer:
You should declare a state on each dropdown and don't declare state in parent.