如果React组件渲染(或者说`执行`)提前,就可以在条件判断里使用Hooks了吗?
问题
mui
的Tab
组件DEMO里面, TabPanel
是通过选择的TabValue
来判断现在要渲染哪个组件.但是竟然可以在TabPanel child组件里使用Hooks,这和react官网的那句话不太一样呀
如果我把child类型改成函数, child组件就又不能用hooks了
改成函数前
https://codesandbox.io/s/lingering-microservice-9xxfjj?file=/...
import * as React from "react";
import Tabs from "@mui/material/Tabs";
import Tab from "@mui/material/Tab";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
function TabPanel(index: number, value: number, children: React.ReactNode) {
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
>
{value === index && (
<Box sx={{ p: 3 }}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
function a11yProps(index: number) {
return {
id: `simple-tab-${index}`,
"aria-controls": `simple-tabpanel-${index}`
};
}
const Tab2Child = (value) => {
const [res, setRes] = React.useState("res");
return (
<h1 id="aaa444">
{value} +++ {res}
</h1>
);
};
const Tab2 = (value) => {
return TabPanel(1, value, Tab2Child(value));
};
export default function BasicTabs() {
const [value, setValue] = React.useState(0);
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
setValue(newValue);
};
return (
<Box sx={{ width: "100%" }}>
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
<Tabs
value={value}
onChange={handleChange}
aria-label="basic tabs example"
>
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
<Tab label="Item Three" {...a11yProps(2)} />
</Tabs>
</Box>
{TabPanel(0, value, <h1>tab 1</h1>)}
{TabPanel(2, value, <h1>tab 3</h1>)}
{Tab2(value)}
</Box>
);
}
改成函数后
https://codesandbox.io/s/pedantic-edison-7zju4s?file=/demo.ts...
import * as React from "react";
import Tabs from "@mui/material/Tabs";
import Tab from "@mui/material/Tab";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
function TabPanel(
index: number,
value: number,
children: () => React.ReactNode
) {
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
>
{value === index && (
<Box sx={{ p: 3 }}>
<Typography>{children()}</Typography>
</Box>
)}
</div>
);
}
function a11yProps(index: number) {
return {
id: `simple-tab-${index}`,
"aria-controls": `simple-tabpanel-${index}`
};
}
const Tab2Child = (value) => {
const [res, setRes] = React.useState();
return (
<h1 id="aaa444">
{value} +++ {res}
</h1>
);
};
const Tab2 = (value) => {
return TabPanel(1, value, () => Tab2Child(value));
};
export default function BasicTabs() {
const [value, setValue] = React.useState(0);
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
setValue(newValue);
};
return (
<Box sx={{ width: "100%" }}>
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
<Tabs
value={value}
onChange={handleChange}
aria-label="basic tabs example"
>
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
<Tab label="Item Three" {...a11yProps(2)} />
</Tabs>
</Box>
{TabPanel(0, value, () => (
<h1>tab 1</h1>
))}
{TabPanel(2, value, () => (
<h1>tab 3</h1>
))}
{Tab2(value)}
</Box>
);
}
回复
1个回答
test
2024-07-06
React 的规则是不能在条件语句中使用 Hooks,因为 Hooks 必须按照它们在组件中声明的顺序运行。当你使用条件语句时,可能会导致 Hooks 的顺序不一致,从而引发问题。
在你的代码里,虽然 TabPanel 组件是通过条件渲染的,但它们的子组件始终使用 Hooks。当条件满足时,组件会正常渲染,但实际上仍然违反了 React Hooks 的规则。这是一个潜在的问题,可能会导致意外的行为。
解决方案:
你可以使用 React 的懒加载特性(React.lazy)来确保组件在需要时才加载,并且始终遵循 Hooks 的规则。修改 Tab2Child 和 Tab2 组件如下:
import * as React from "react";
const Tab2Child = React.lazy(() => {
return new Promise((resolve) => {
resolve({
default: (value) => {
const [res, setRes] = React.useState("res");
return (
<h1 id="aaa444">
{value} +++ {res}
</h1>
);
},
});
});
});
const Tab2 = (value) => {
return (
<React.Suspense fallback={<div>Loading...</div>}>
<TabPanel index={1} value={value} children={<Tab2Child />} />
</React.Suspense>
);
};
这样,代码依然会遵循 React Hooks 的规则,同时实现条件渲染。你要注意,在使用React.lazy 时,需要包裹在 React.Suspense 组件中,要提供一个 fallback 组件,方便在组件加载期间显示。
回复
适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容