React.memo 不起作用 - 我错过了啥?
Posted
技术标签:
【中文标题】React.memo 不起作用 - 我错过了啥?【英文标题】:React.memo isn't working - what am I missing?React.memo 不起作用 - 我错过了什么? 【发布时间】:2020-09-14 10:07:27 【问题描述】:我正在重构我们的一些组件,因此我正在尝试合并记忆,因为某些组件可能使用相同的值重新呈现(例如,热链接的图像 URL,除非它们是一样的)。
我有一个简单的组件:
const CardHeader = props =>
// img is a stringand showAvatar is a boolean but it's always true
const ..., showAvatar, img = props;
return (
<CardHeader>
<ListItem>
// AvatarImage shouldn't re-render if img is the same as previous
showAvatar && <AvatarImage img=img />
</ListItem>
</CardHeader>
);
然后是AvatarImage:
const AvatarImage = React.memo(props =>
console.log("why is this still re-rendering when the img value hasn't changed?");
const img = props;
return (
<ListItemAvatar>
img ?
<Avatar src=img />
:
<Avatar>
Some initials
</Avatar>
</ListItemAvatar>
);
);
我也尝试过传入备忘录的第二个参数:
(prevProps, nextProps) =>
return true; // Don't re-render!
但是 console.log 仍然每次都显示。我显然在这里遗漏了一些东西,或者不太明白这是如何工作的。这个组件低了几个级别,但是如果它每次都可用,它就会传入 img,所以我希望它知道如果 img 在之前的渲染中被传递,并且它知道不再重新渲染它是一样的但由于某种原因,它确实如此?
谢谢大家。非常感谢。
【问题讨论】:
1.img
是字符串吗? 2. showAvatar
是否有机会在这些渲染之间发生变化?
是的,img 是一个字符串(“https://.........jpg”)。在这种情况下,显示头像始终为真。对不起,我应该提到这一点。我会更新的。
能否展示一下 CardHeader 是如何使用的以及图像值是如何传递给它的?
好像信息丢失了,这个bug现在不在我们面前。如果你可以用codesandbox.io 或fiddle 重现,那就太好了
@user.io 你找到原因了吗?现在面临同样的问题。所有道具都保持不变,React.memo
无论如何都会重新渲染。
【参考方案1】:
好吧,要么showAvatar
并不总是正确,要么CardHeader
ListItem
组件神奇地决定是否显示孩子
示例
const useState, useEffect, memo, createContext, useContext = React;
const getAvatars = () => Promise.resolve([
src: 'https://i.picsum.photos/id/614/50/50.jpg'
,
src: 'https://i.picsum.photos/id/613/50/50.jpg'
])
const Avatar = (src) =>
console.log('avatar render');
return <img src=src />
const MemoAvatarToggle = memo((src) =>
console.log('memo avatar with \'expression &&\' render');
return <div>
src ? <img src=src /> : <div>Test </div>
</div>
)
const CardHeader = (children) =>
const luck = Boolean(Math.floor(Math.random() * 1.7));
return <div>
luck && children
</div>
const ListItem = (children) =>
return <div>
children
</div>
const ShowAvatarContext = createContext()
const App = (props) =>
const [avatars, setAvatars] = useState([]);
const [toggle, setToggle] = useState(false);
const [showAvatar, setShowAvatar] = useContext(ShowAvatarContext);
useEffect(() =>
let isUnmounted = false;
let handle = null;
setTimeout(() =>
if(isUnmounted)
return;
setShowAvatar(true);
, 500);
getAvatars()
.then(avatars =>
if(isUnmounted)
return;
setAvatars(avatars)
)
const toggle = () =>
setToggle(prev => !prev);
handle = setTimeout(toggle, 1000);
//setShowAvatar(prev => !prev);
handle = setTimeout(toggle, 1000);
return () =>
isUnmounted = true;
clearTimeout(handle);
, []);
return <div>
<CardHeader>
<ListItem>
showAvatar && avatars.map((avatar, index) => <MemoAvatarToggle key=index src=avatar.src/>)
</ListItem>
</CardHeader>
toggle ? 1 : 0
</div>
const ShowAvatarProvider = (children) =>
const state = useState(false);
return <ShowAvatarContext.Provider value=state>
children
</ShowAvatarContext.Provider>
ReactDOM.render(
<ShowAvatarProvider>
<App/>
</ShowAvatarProvider>,
document.getElementById('root')
);
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div id="root"></div>
【讨论】:
【参考方案2】:您是否启用了StrictMode
?这将导致使用React.memo
记忆的组件渲染两次。
更多信息:
https://reactjs.org/docs/strict-mode.html My React Component is rendering twice because of Strict Mode【讨论】:
以上是关于React.memo 不起作用 - 我错过了啥?的主要内容,如果未能解决你的问题,请参考以下文章
用 puppeteer 更改 IP 地址似乎不起作用。我错过了啥吗?
添加了 Springfox Swagger-UI 但它不起作用,我错过了啥?
在 Flexbox 中居中不起作用。啥是高度、宽度、显示和位置要求?我错过了啥? [复制]