React Hooks - 防止子组件渲染
React Hooks - Preventing child components from rendering
作为React的新手,组件的重新渲染似乎是一件不能做的事情。
因此,例如,如果我想创建一个遵循这种架构的菜单:
App
是 Menu
的父级,它有一个 map
函数创建 MenuItem
个组件
- 菜单项来自数据源(这里是
const data
)
- 当我点击
MenuItem
时,它会使用选定的 MenuItem
值更新状态
目前还好,只是所有的组件都重新渲染了(见各种console.log
)
代码如下:
应用程序
import React, { useState} from "react"
import Menu from "./menu";
function App() {
const data = ["MenuItem1", "MenuItem2", "MenuItem3", "MenuItem4", "MenuItem5", "MenuItem6"]
const [selectedItem, setMenuItem] = useState(null)
const handleMenuItem = (menuItem) => {
setMenuItem(menuItem)
}
return (
<div className="App">
<Menu items = {data} handleMenuItem = {handleMenuItem}></Menu>
<div>{selectedItem}</div>
</div>
);
}
export default App;
菜单
import React from "react";
import MenuItem from "./menuItem";
const Menu = (props) => {
return (
<>
{props.items.map((item, index) => {
return <MenuItem key = {index} handleMenuItem = {props.handleMenuItem} value = {item}></MenuItem>
})
}
{console.log("menuItem")}
</>
)
};
export default React.memo(Menu);
菜单项
import React from "react";
const MenuItem = (props) => {
return (
<>
<div onClick={() => props.handleMenuItem(props.value)}>
<p>{props.value}</p>
</div>
{console.log("render du MenuItem")}
</>
)
};
export default React.memo(MenuItem);
如您所见,我在 MenuItem
的末尾使用了 React.memo
但它不起作用,PureComponent
如果有人有想法,能得到一些建议就太好了。
祝你有美好的一天
这里有很多东西要拆开,让我们开始吧。
钩子旨在防止 re-rendering 组件不必要地使用的方法是确保您使用任何未更改变量的相同实例,尤其是对象、函数和数组。我这么说是因为字符串、数字和布尔值相等很简单 'abc' === 'abc'
解析为 true,但 [] === []
将是 false,因为它们是两个不同的空数组进行比较,对象和函数在 JS 中相等只有当被比较的两侧是完全相同的项目时,数组才 returns 为真。
就是说,React 提供了缓存值的方法,并且仅在需要更新时(因为它们的依赖项发生变化)才更新它们(通过创建新实例)。让我们从您的 app.js
开始
import React, {useState, useCallback} from "react"
import Menu from "./menu";
// move this out of the function so that a new copy isn't created every time
// the App component re-renders
const data = ["MenuItem1", "MenuItem2", "MenuItem3", "MenuItem4", "MenuItem5", "MenuItem6"]
function App() {
const [selectedItem, setMenuItem] = useState(null);
// cache this with useCallback. The second parameter (the dependency
// array) is an empty array because there are no items that, should they
// change, we should create a new copy. That is to say we should never
// need to make a new copy because we have no dependencies that could
// change. This will now be the same instance of the same function each
// re-render.
const handleMenuItem = useCallback((menuItem) => setMenuItem(menuItem), []);
return (
<div className="App">
<Menu items={data} handleMenuItem={handleMenuItem}></Menu>
<div>{selectedItem}</div>
</div>
);
}
export default App;
以前,每次 App 组件 re-rendered 时,handleMenuItem 都被设置为该函数的一个新副本,并且 data
也被设置为一个新数组(具有相同的条目) re-render。这将导致每次 App 为 re-rendered 时子组件 (Menu) re-render。我们不想要那样。如果绝对必要,我们只希望子组件 re-render。
接下来是菜单组件。这里几乎没有变化,尽管我会敦促你不要在你的 JSX 中的 =
周围放置空格(key={index}
而不是 key = {index}
.
import React from "react";
import MenuItem from "./menuItem";
const Menu = (props) => {
return (
<>
{props.items.map((item, index) => {
return <MenuItem key={index} handleMenuItem={props.handleMenuItem} value={item}/>
})
}
{console.log("menuItem")}
</>
)
};
export default React.memo(Menu);
对于 MenuItem,让我们缓存点击处理程序。
import React from "react";
const MenuItem = (props) => {
// cache this function
const handleClick = useCallback(() => props.handleMenuItem(props.value), [props.value]);
return (
<>
<div onClick={handleClick}>
<p>{props.value}</p>
</div>
{console.log("render du MenuItem")}
</>
)
};
export default React.memo(MenuItem);
用 useCallback 包装您的 handleMenuItem
函数,以避免在函数更改时重新呈现。这将创建一个函数引用,它将在 MenuItem
中用作 props 并且将避免重读,因为它始终是相同的函数实例。
在这种情况下,我使用了一个空的依赖项数组,这对您的用例来说是正确的。如果您的函数有任何状态引用,则应将它们添加到数组中。
const handleMenuItem = useCallback((menuItem) => {
setMenuItem(menuItem);
}, []);
作为React的新手,组件的重新渲染似乎是一件不能做的事情。
因此,例如,如果我想创建一个遵循这种架构的菜单:
App
是 Menu
的父级,它有一个 map
函数创建 MenuItem
个组件
- 菜单项来自数据源(这里是
const data
) - 当我点击
MenuItem
时,它会使用选定的MenuItem
值更新状态
目前还好,只是所有的组件都重新渲染了(见各种console.log
)
代码如下:
应用程序
import React, { useState} from "react"
import Menu from "./menu";
function App() {
const data = ["MenuItem1", "MenuItem2", "MenuItem3", "MenuItem4", "MenuItem5", "MenuItem6"]
const [selectedItem, setMenuItem] = useState(null)
const handleMenuItem = (menuItem) => {
setMenuItem(menuItem)
}
return (
<div className="App">
<Menu items = {data} handleMenuItem = {handleMenuItem}></Menu>
<div>{selectedItem}</div>
</div>
);
}
export default App;
菜单
import React from "react";
import MenuItem from "./menuItem";
const Menu = (props) => {
return (
<>
{props.items.map((item, index) => {
return <MenuItem key = {index} handleMenuItem = {props.handleMenuItem} value = {item}></MenuItem>
})
}
{console.log("menuItem")}
</>
)
};
export default React.memo(Menu);
菜单项
import React from "react";
const MenuItem = (props) => {
return (
<>
<div onClick={() => props.handleMenuItem(props.value)}>
<p>{props.value}</p>
</div>
{console.log("render du MenuItem")}
</>
)
};
export default React.memo(MenuItem);
如您所见,我在 MenuItem
的末尾使用了 React.memo
但它不起作用,PureComponent
如果有人有想法,能得到一些建议就太好了。
祝你有美好的一天
这里有很多东西要拆开,让我们开始吧。
钩子旨在防止 re-rendering 组件不必要地使用的方法是确保您使用任何未更改变量的相同实例,尤其是对象、函数和数组。我这么说是因为字符串、数字和布尔值相等很简单 'abc' === 'abc'
解析为 true,但 [] === []
将是 false,因为它们是两个不同的空数组进行比较,对象和函数在 JS 中相等只有当被比较的两侧是完全相同的项目时,数组才 returns 为真。
就是说,React 提供了缓存值的方法,并且仅在需要更新时(因为它们的依赖项发生变化)才更新它们(通过创建新实例)。让我们从您的 app.js
开始import React, {useState, useCallback} from "react"
import Menu from "./menu";
// move this out of the function so that a new copy isn't created every time
// the App component re-renders
const data = ["MenuItem1", "MenuItem2", "MenuItem3", "MenuItem4", "MenuItem5", "MenuItem6"]
function App() {
const [selectedItem, setMenuItem] = useState(null);
// cache this with useCallback. The second parameter (the dependency
// array) is an empty array because there are no items that, should they
// change, we should create a new copy. That is to say we should never
// need to make a new copy because we have no dependencies that could
// change. This will now be the same instance of the same function each
// re-render.
const handleMenuItem = useCallback((menuItem) => setMenuItem(menuItem), []);
return (
<div className="App">
<Menu items={data} handleMenuItem={handleMenuItem}></Menu>
<div>{selectedItem}</div>
</div>
);
}
export default App;
以前,每次 App 组件 re-rendered 时,handleMenuItem 都被设置为该函数的一个新副本,并且 data
也被设置为一个新数组(具有相同的条目) re-render。这将导致每次 App 为 re-rendered 时子组件 (Menu) re-render。我们不想要那样。如果绝对必要,我们只希望子组件 re-render。
接下来是菜单组件。这里几乎没有变化,尽管我会敦促你不要在你的 JSX 中的 =
周围放置空格(key={index}
而不是 key = {index}
.
import React from "react";
import MenuItem from "./menuItem";
const Menu = (props) => {
return (
<>
{props.items.map((item, index) => {
return <MenuItem key={index} handleMenuItem={props.handleMenuItem} value={item}/>
})
}
{console.log("menuItem")}
</>
)
};
export default React.memo(Menu);
对于 MenuItem,让我们缓存点击处理程序。
import React from "react";
const MenuItem = (props) => {
// cache this function
const handleClick = useCallback(() => props.handleMenuItem(props.value), [props.value]);
return (
<>
<div onClick={handleClick}>
<p>{props.value}</p>
</div>
{console.log("render du MenuItem")}
</>
)
};
export default React.memo(MenuItem);
用 useCallback 包装您的 handleMenuItem
函数,以避免在函数更改时重新呈现。这将创建一个函数引用,它将在 MenuItem
中用作 props 并且将避免重读,因为它始终是相同的函数实例。
在这种情况下,我使用了一个空的依赖项数组,这对您的用例来说是正确的。如果您的函数有任何状态引用,则应将它们添加到数组中。
const handleMenuItem = useCallback((menuItem) => {
setMenuItem(menuItem);
}, []);