React.memo 2nd 参数依赖函数未按预期工作 [英] React.memo 2nd Parameter Dependency Function Not Working as Expected

查看:38
本文介绍了React.memo 2nd 参数依赖函数未按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个我构建的简单示例,它显示传递给 React.memo 的第二个参数的函数似乎没有像我期望的那样获得以前的属性值.此示例是呈现为按钮的扬声器(对象)的简单列表.按钮上的 onClick 事件导致传递给父组件,父组件中的状态发生变化,并且新的渲染应该只显示更新的组件.

然而,不管之前的状态如何,之前传入的总是和新的状态一样.

示例位于此 URL:https://stackblitz.com/edit/react-upe9vu

在组件 Hello.js 中,当前导入用于 ./Speaker 但是,如果您将其更改为 ./SpeakerWithMemo,如图所示在上面的行中,单击按钮无法更新收藏夹"状态.

我希望在 SpeakerWithMemo.js 中,第 12 行的 console.log 会显示 prevProps.speaker.favorite 与 nextProps.speaker.favorite 不同.

相关代码如下:

Hello.js

import React, { useState } from "react";//没有更新发生在按钮点击.//从./SpeakerWithMemo"导入扬声器;//更新按预期在按钮点击时发生从./Speaker"导入扬声器;导出默认值 () =>{const 扬声器阵列 = [{ name: Crockford", id: 101, 最喜欢的: true },{ name: Gupta", id: 102, 最喜欢的: false },{ name: Ailes", id: 103, 最喜欢的: true },];const [speakers, setSpeakers] = useState(speakersArray);const clickFunction = (speakerIdClicked) =>{var SpeakersArrayUpdated = Speakers.map((rec) => {如果(rec.id === SpeakerIdClicked){rec.favorite = !rec.favorite;}返回记录;});setSpeakers(speakersArrayUpdated);};返回 (<div>{speakers.map((rec) => {返回 (<扬声器扬声器={rec}键={rec.id}clickFunction={() =>{clickFunction(rec.id);}}></扬声器>);})}

);};

SpeakerWithMemo.js

从反应"导入反应;导出默认 React.memo(({ 扬声器, clickFunction }) =>{console.log(`渲染扬声器 ${speaker.name} ${speaker.favorite}`);返回 (<button onClick={clickFunction}>使用备忘录 {speaker.name} {speaker.id}{""}{speaker.favorite === true ?真实":假"});},(prevProps, nextProps) =>{控制台.日志(`备忘录:${prevProps.speaker.favorite === nextProps.speaker.favorite} ${prevProps.speaker.name最喜欢的:上一个:${prevProps.speaker.favorite} 下一个:${nextProps.speaker.favorite}`);return prevProps.speaker.favorite === nextProps.speaker.favorite;});

解决方案

备忘录没有按预期工作,因为您有一个状态突变.通过不返回新的对象引用,react 会在重新渲染时保释,即 props.speaker 对象引用永远不会改变,因此 react 假设它与更深入地检查无关.

const clickFunction = (speakerIdClicked) =>{var SpeakersArrayUpdated = Speakers.map((rec) => {如果(rec.id === SpeakerIdClicked){rec.favorite = !rec.favorite;//<-- 改变你尝试记忆的对象}返回记录;});setSpeakers(speakersArrayUpdated);};

对于您尝试更新的元素,您需要返回一个 new 对象引用.此外,当像这样排队切换状态更新时,您应该使用功能状态更新.

const clickFunction = SpeakerIdClicked =>{setSpeakers(speakers =>扬声器.map(rec =>rec.id === SpeakerIdClicked?{...rec,//<-- 浅拷贝现有值最喜欢的:!rec.favorite//<-- 更新字段/属性}: 记录));};

https://react-eyvskj.stackblitz.io

I have a trivial example I built that shows the function passed into the second parameter of React.memo seems to not get the previous property value as I would expect. This example is a simple list of speakers (objects) that are rendered as buttons. The onClick event on the button caused passed up to the parent component, state changes in the parent, and a new render should show just the updated component.

However, regardless of the previous state, the passed in previous is always the same as the new state.

The example is at this URL: https://stackblitz.com/edit/react-upe9vu

In the component Hello.js the current import is for ./Speaker however, if you change that to ./SpeakerWithMemo as shown in the line above, the button click fails to update the "favorite" status.

I would expect that in SpeakerWithMemo.js that the console.log at line 12 would show the prevProps.speaker.favorite different then the nextProps.speaker.favorite.

The relevant code is below:

Hello.js

import React, { useState } from "react";

// NO UPDATE HAPPENS ON BUTTON CLICK.
//import Speaker from "./SpeakerWithMemo";

// UPDATE HAPPENS AS EXPECTED ON BUTTON CLICK
import Speaker from "./Speaker";

export default () => {
  const speakersArray = [
    { name: "Crockford", id: 101, favorite: true },
    { name: "Gupta", id: 102, favorite: false },
    { name: "Ailes", id: 103, favorite: true },
  ];

  const [speakers, setSpeakers] = useState(speakersArray);

  const clickFunction = (speakerIdClicked) => {
    var speakersArrayUpdated = speakers.map((rec) => {
      if (rec.id === speakerIdClicked) {
        rec.favorite = !rec.favorite;
      }
      return rec;
    });
    setSpeakers(speakersArrayUpdated);
  };

  return (
    <div>
      {speakers.map((rec) => {
        return (
          <Speaker
            speaker={rec}
            key={rec.id}
            clickFunction={() => {
              clickFunction(rec.id);
            }}
          ></Speaker>
        );
      })}
    </div>
  );
};

SpeakerWithMemo.js

import React from "react";

export default React.memo(
  ({ speaker, clickFunction }) => {
    console.log(`Rendering Speaker ${speaker.name} ${speaker.favorite}`);
    return (
      <button onClick={clickFunction}>
        With Memo {speaker.name} {speaker.id}{" "}
        {speaker.favorite === true ? "true" : "false"}
      </button>
    );
  },
  (prevProps, nextProps) => {
    console.log(
      `memo: ${prevProps.speaker.favorite === nextProps.speaker.favorite} ${
        prevProps.speaker.name
      } fav: prev: ${prevProps.speaker.favorite} next: ${
        nextProps.speaker.favorite
      } `
    );
    return prevProps.speaker.favorite === nextProps.speaker.favorite;
  }
);

解决方案

The memo isn't working quite as expected because you've a state mutation. By not returning a new object reference react bails on rerendering, i.e. the props.speaker object reference never changes so react assumes it is irrelevant to check more deeply.

const clickFunction = (speakerIdClicked) => {
  var speakersArrayUpdated = speakers.map((rec) => {
    if (rec.id === speakerIdClicked) {
      rec.favorite = !rec.favorite; // <-- Mutates the object you try to memoize
    }
    return rec;
  });
  setSpeakers(speakersArrayUpdated);
};

For the element you are trying to update you need to return a new object reference. Also, when queuing toggle state updates like this you should use a functional state update.

const clickFunction = speakerIdClicked => {
  setSpeakers(speakers =>
    speakers.map(rec =>
      rec.id === speakerIdClicked
        ? {
            ...rec, // <-- shallow copy existing value
            favorite: !rec.favorite // <-- update field/property
          }
        : rec
    )
  );
};

https://react-eyvskj.stackblitz.io

这篇关于React.memo 2nd 参数依赖函数未按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆