简体   繁体   English

在什么情况下它会在使用 react 自定义钩子时重新渲染

[英]In what condition it will re-render while using react custom hooks

I tried a sample in using react hook, make it a custom hook.我尝试了一个使用 react hook 的示例,使其成为自定义 hook。 The problem is the simple hook useCount() goes fine, but the hook useCarHighlight() intending to switch highlight line would not cause re-render.问题是简单的钩子useCount()良好,但是打算切换高亮线的钩子useCarHighlight()不会导致重新渲染。 I see it is the same of the two, is anything wrong I should attention for about this?我看这两者是一样的,我应该注意什么问题吗?

I made a sandbox here: https://codesandbox.io/s/typescript-j2xtf我在这里做了一个沙箱: https : //codesandbox.io/s/typescript-j2xtf

Some code below:下面的一些代码:

// index.tsx

import * as React from "react";
import * as ReactDOM from "react-dom";
import useCarHighlight, { Car } from "./useCarHighlight";
import useCount from "./useCount";

const myCars: Car[] = [
  { model: "C300", brand: "benz", price: 29000, ac: "auto ac" },
  { model: "Qin", brand: "byd", price: 9000 }
];

const App = () => {
  const { cars, setHighlight } = useCarHighlight(myCars, "Qin");
  const { count, increase, decrease } = useCount(10);
  console.log(
    `re-render at ${new Date().toLocaleTimeString()}, 
    Current highlight: ${
      cars.find(c => c.highlight)?.model
    }`
  );
  return (
    <div>
      <ul>
        {cars.map(car => {
          const { model, highlight, brand, price, ac = "no ac" } = car;
          return (
            <li
              key={model}
              style={{ color: highlight ? "red" : "grey" }}
            >{`[${brand}] ${model}: $ ${price}, ${ac}`}</li>
          );
        })}
      </ul>
      <button onClick={() => setHighlight("C300")}>highlight C300</button>
      <button onClick={() => setHighlight("Qin")}>highlight Qin</button>
      <hr />

      <h1>{`Count: ${count}`}</h1>
      <button onClick={() => increase()}>+</button>
      <button onClick={() => decrease()}>-</button>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));



// useCarHighlight.ts

import { useState } from "react";

export type Car = {
  model: string;
  brand: string;
  price: number;
  ac?: "auto ac" | "manual ac";
};

export default function(
  initialCars: Car[],
  initialSelectedModel: string
): {
  cars: Array<Car & { highlight: boolean }>;
  setHighlight: (selMod: string) => void;
} {
  const carsHighlight = initialCars.map(car => ({
    ...car,
    highlight: initialSelectedModel === car.model
  }));

  const [cars, setCars] = useState(carsHighlight);
  const setHighlight = (selMod: string) => {
    cars.forEach(car => {
      car.highlight = car.model === selMod;
    });
    setCars(cars);
  };

  return {
    cars,
    setHighlight
  };
}




// useCount.ts
import { useState } from "react";

export default function useCount(initialCount: number) {
  const [state, setState] = useState(initialCount);
  const increase = () => setState(state + 1);
  const decrease = () => setState(state - 1);
  return {
    count: state,
    increase,
    decrease
  };
}

Unlike class components, mutating state of hooks does not queue a re-render, when using hooks you have to update your state in an immutable way.与类组件不同,钩子的改变状态不会排队重新渲染,当使用钩子时,您必须以不可变的方式更新状态。

Also, when calculating the next state based on the previous state it is recommended to use a functional update and read the previous state from the first argument of the function.此外,当基于前一个状态计算下一个状态时,建议使用函数更新并从函数的第一个参数读取前一个状态。

const setHighlight = (selMod: string) => {
  setCars(prevState =>
    prevState.map(car => ({
      ...car,
      highlight: car.model === selMod
    }))
  );
};

Here is a good resource about immutable update patterns这是一个关于不可变更新模式的好资源

Dont use forEach in setHighlight , use map instead不要在setHighlight使用forEachsetHighlight使用map

  const setHighlight = (selMod: string) => {
    const newCars = cars.map(car => ({
      ...car,
      highlight: car.model === selMod
    }));
    setCars(newCars);
  };

Use map instead of forEach as the address of car object isn't getting changed when you update highlight property in car.使用 map 而不是 forEach 因为当您更新 car 中的 highlight 属性时,car 对象的地址不会改变。

const setHighlight = (selMod: string) => {
let carsTemp = cars.map(car => ({
  ...car,
  highlight : car.model === selMod
}));
setCars(carsTemp);};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM