在内部组件中使用钩子
Using hooks in inner Component
我正在尝试使用 Hook 创建组件,但我遇到了一个奇怪的问题。
我在我的代码中使用 mapbox-gl。为了初始化 mapbox-gl,我必须等到 dom 组件加载完毕。 (useLayoutEffect 或 useEffect)
初始显示没有问题,但是当我按下按钮(L72)时,由 mapbox-gl 创建的 canvas 被卸载,没有控制台错误。
我尝试将MyMap组件移到Tile组件(L35-L45)之外,然后没有发生上述问题。
我是不是用错了 Hook?
我的示例完整代码如下。
[CodeSandbox]
这是Map.tsx中的节选:
export const Tile: React.FunctionComponent<PropsType> = ({
mapComponentLoaded,
trigger,
triggered
}) => {
const classes = useStyles({});
React.useLayoutEffect(() => { // or useEffect
// init mapbox-gl
mapComponentLoaded();
}, []); // run at once
// it doesn't works. if you clicked the button, the canvas under div#map would unmount.
const MyMap = (props: { triggered: boolean }) => (
<Paper className={classes.content}>
<div id="map" className={classes.map} />
<Typography>{props.triggered ? "fired" : "not fired"}</Typography>
</Paper>
);
return (
<div className={classes.root}>
<Grid container spacing={1} className={classes.root}>
<Grid item xs={12}>
<Button variant="contained" color="primary" onClick={() => trigger()}>
Add Boundary
</Button>
</Grid>
<Grid item xs={12} className={classes.map}>
<MyMap triggered={triggered} />
</Grid>
</Grid>
</div>
);
};
谢谢。
当你在一个功能组件中定义一个组件时,在每次渲染时都会创建一个新的引用,因此,react 不会重新渲染,而是重新挂载它已创建新组件
当您将组件从功能组件中取出时,函数的引用不会改变,因此 React 会正确呈现它
现在另一种可行的方法是,如果不是将 MyMap
作为组件呈现,而是将其作为函数调用。
export const Tile: React.FunctionComponent<PropsType> = ({
mapComponentLoaded,
trigger,
triggered
}) => {
const classes = useStyles({});
React.useLayoutEffect(() => { // or useEffect
// init mapbox-gl
mapComponentLoaded();
}, []); // run at once
// it doesn't works. if you clicked the button, the canvas under div#map would unmount.
const MyMap = (props: { triggered: boolean }) => (
<Paper className={classes.content}>
<div id="map" className={classes.map} />
<Typography>{props.triggered ? "fired" : "not fired"}</Typography>
</Paper>
);
return (
<div className={classes.root}>
<Grid container spacing={1} className={classes.root}>
<Grid item xs={12}>
<Button variant="contained" color="primary" onClick={() => trigger()}>
Add Boundary
</Button>
</Grid>
<Grid item xs={12} className={classes.map}>
{MyMap({triggered})}
</Grid>
</Grid>
</div>
);
};
Working demo with second approach
P.S. However taking the definition out of function definition is a much better approach as it gives you the flexibility to add more
performance optimizations using React.memo
and also to use hooks
within this component
我正在尝试使用 Hook 创建组件,但我遇到了一个奇怪的问题。
我在我的代码中使用 mapbox-gl。为了初始化 mapbox-gl,我必须等到 dom 组件加载完毕。 (useLayoutEffect 或 useEffect)
初始显示没有问题,但是当我按下按钮(L72)时,由 mapbox-gl 创建的 canvas 被卸载,没有控制台错误。
我尝试将MyMap组件移到Tile组件(L35-L45)之外,然后没有发生上述问题。
我是不是用错了 Hook?
我的示例完整代码如下。
[CodeSandbox]
这是Map.tsx中的节选:
export const Tile: React.FunctionComponent<PropsType> = ({
mapComponentLoaded,
trigger,
triggered
}) => {
const classes = useStyles({});
React.useLayoutEffect(() => { // or useEffect
// init mapbox-gl
mapComponentLoaded();
}, []); // run at once
// it doesn't works. if you clicked the button, the canvas under div#map would unmount.
const MyMap = (props: { triggered: boolean }) => (
<Paper className={classes.content}>
<div id="map" className={classes.map} />
<Typography>{props.triggered ? "fired" : "not fired"}</Typography>
</Paper>
);
return (
<div className={classes.root}>
<Grid container spacing={1} className={classes.root}>
<Grid item xs={12}>
<Button variant="contained" color="primary" onClick={() => trigger()}>
Add Boundary
</Button>
</Grid>
<Grid item xs={12} className={classes.map}>
<MyMap triggered={triggered} />
</Grid>
</Grid>
</div>
);
};
谢谢。
当你在一个功能组件中定义一个组件时,在每次渲染时都会创建一个新的引用,因此,react 不会重新渲染,而是重新挂载它已创建新组件
当您将组件从功能组件中取出时,函数的引用不会改变,因此 React 会正确呈现它
现在另一种可行的方法是,如果不是将 MyMap
作为组件呈现,而是将其作为函数调用。
export const Tile: React.FunctionComponent<PropsType> = ({
mapComponentLoaded,
trigger,
triggered
}) => {
const classes = useStyles({});
React.useLayoutEffect(() => { // or useEffect
// init mapbox-gl
mapComponentLoaded();
}, []); // run at once
// it doesn't works. if you clicked the button, the canvas under div#map would unmount.
const MyMap = (props: { triggered: boolean }) => (
<Paper className={classes.content}>
<div id="map" className={classes.map} />
<Typography>{props.triggered ? "fired" : "not fired"}</Typography>
</Paper>
);
return (
<div className={classes.root}>
<Grid container spacing={1} className={classes.root}>
<Grid item xs={12}>
<Button variant="contained" color="primary" onClick={() => trigger()}>
Add Boundary
</Button>
</Grid>
<Grid item xs={12} className={classes.map}>
{MyMap({triggered})}
</Grid>
</Grid>
</div>
);
};
Working demo with second approach
P.S. However taking the definition out of function definition is a much better approach as it gives you the flexibility to add more performance optimizations using
React.memo
and also to use hooks within this component