Reputation: 3
I got three component here. MainComponent is including with other two. And what I want to do is, changes in select input in WebHeaderComponent would refresh sidemenucomponent layout. But error prompted when i try to do so.
MainComponent
-> WebHeaderComponent
-> SideMenuComponent
MainComponent.tsx
const { Content } = Layout;
const MainComopnent: FunctionComponent = () => {
const [collapsed, setCollapsed] = useState(false);
const [menuList, setMenuList] = useState([]);
const services = useContext(ServicesContext);
const { MenuService } = services;
const { AuthenticationService } = services;
useEffect(() => {
const requestOption = {
method: "post",
body: JSON.stringify({
userCode: AuthenticationService.getUserModel().userCode,
roleId: AuthenticationService.getUserModel().roleId
})
}
MenuApi.getSideMenu(requestOption).then((result) => {
console.log(result);
const temp = MenuService.groupMenu(result);
setMenuList(temp);
});
}, []);
const value = { collapsed, setCollapsed };
return (
<SideMenuCollapsedContext.Provider value={value}>
<Layout className="layout">
<SideMenuComponent menuList={MenuService.getGroupMenu()}></SideMenuComponent>
<Layout className="site-layout">
<WebHeaderComponent></WebHeaderComponent>
<Content
className="site-layout-background"
style={{
margin: "24px 16px",
padding: 24,
minHeight: 280,
overflowY: "scroll",
}}
>
<AppRoutes />
</Content>
</Layout>
</Layout>
</SideMenuCollapsedContext.Provider>
);
};
export default MainComopnent;
WebHeaderComponent.tsx
const { Header } = Layout;
const WebHeaderComponent = () => {
const services = useContext(ServicesContext);
const { MenuService } = services;
const { AuthenticationService } = services;
const { UserInfoService } = services;
const [userRoleList, setUserRoleList] = useState<Array<any>>([]);
const {collapsed, setCollapsed} = useContext(SideMenuCollapsedContext);
const toggle = () => {
setCollapsed(!collapsed);
};
useEffect(() => {
const data = { userId: AuthenticationService.getUserModel().userId};
SysUserApi.searchSysUserRole(data).then((res) => {
setUserRoleList(res)
})
},[]);
const handleRoleChange = (selectedRoleId) => {
console.log('before: ' + selectedRoleId);
AuthenticationService.setRoleId(selectedRoleId);
console.log('after: ' + AuthenticationService.getUserModel().roleId)
}
return (
<Header className="site-layout-background" style={{ padding: 0 }}>
{React.createElement(
collapsed ? MenuUnfoldOutlined : MenuFoldOutlined,
{
className: "trigger",
style: { paddingLeft: "10px", fontSize: "20px" },
onClick: toggle,
}
)}
<div
style={{
float: "right",
paddingRight: "20px",
display: "flex",
alignItems: "center",
}}
>
<div><span>用戶:{AuthenticationService.getUserModel().userName}</span></div>
<div style={{ paddingLeft: "10px" }}>
<span>公司-角色:</span>
<Select
style={{ width: 120 }}
defaultValue={AuthenticationService.getUserModel().roleId}
onChange={handleRoleChange}
>
{userRoleList.map(item => (
<option
key={item.roleId}
value={item.roleId}
>
{item.roleName}
</option>
))}
</Select>
</div>
<div style={{ paddingLeft: "10px" }}>
<Button type="primary"> Sign Out </Button>
</div>
</div>
</Header>
);
}
export default WebHeaderComponent;
SideMenuComponent.tsx
const { Sider } = Layout;
const { SubMenu } = Menu;
const createSubMenus = (menuList): any => {
const menus: any = [];
for (const subMenuItem of menuList) {
if (subMenuItem.children && subMenuItem.children.length > 0) {
menus.push(
<SubMenu
key={subMenuItem.funcId}
title={
<span>
<MailOutlined />
<span className="fontWt">{subMenuItem.funcName}</span>
</span>
}
>
{createSubMenus(subMenuItem.children)}
</SubMenu>
);
} else {
menus.push(
<Menu.Item key={subMenuItem.funcId + subMenuItem.parentId}>
{subMenuItem.funcName}
<Link to={"/app" + subMenuItem.funcUrl} replace></Link>
</Menu.Item>
);
}
}
return menus;
};
const SideMenuComponent = ({ menuList }) => {
const value = useContext(SideMenuCollapsedContext);
const [subMenuList, setSubMenuList] = useState([]);
const { collapsed, setCollapsed } = value;
useEffect(() => {
setSubMenuList(createSubMenus(menuList));
}, [menuList]);
const handleCollapsed = (collapsed) => {
setCollapsed(collapsed);
};
return (
<Sider collapsible collapsed={collapsed} onCollapse={handleCollapsed}>
<div className="logo" />
<Menu theme="dark" mode="inline" defaultSelectedKeys={["1"]}>
{/* <Menu.Item key="1" icon={<UserOutlined />}>
<Link to="/app/producttomms">Share Product to MMS</Link>
</Menu.Item>
<Menu.Item key="2" icon={<UserOutlined />}>
<Link to="/app/paymentorderanalyzer">Payment Order Analyzer</Link>
</Menu.Item>
<Menu.Item key="3" icon={<UserOutlined />}>
<Link to="/app/masterdatainitializer">Master Data Initializer</Link>
</Menu.Item> */}
{subMenuList}
</Menu>
</Sider>
);
};
export default SideMenuComponent;
In WebHeaderComponent, I got a select input below. What I do is updating a value in context once I change my value from my select input, I prefer sideMenuComponent would be refreshed with new menulist which come from context.
However, error message is prompted.
Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application.
Upvotes: 0
Views: 164
Reputation: 4938
Lift your state up to the common ancestor (i.e Parent).
Since both can access the state, you could pass the callback from one child to update the parent.
Which in turn updates another child since both children share the same state.
export default function Parent() {
const [text, setText] = React.useState('not yet updated');
return (
<div>
<Child1 text={text} />
<Child2 onClick={setText} />
</div>
);
}
function Child1({ text }) {
return <p>{text}</p>
}
function Child2({ onClick }) {
return <button onClick={() => onClick('Child2 updated the state')}>Update</button>
}
Upvotes: 0