如何使用自定义挂钩和 useContext 仅呈现相关组件

How to render only the concerned component with a custom hook and useContext

我正在尝试基于 useContext 创建一个 自定义挂钩 useFocus 以仅将焦点设置在组件 i select. 它可以工作,但其他组件正在渲染,即使我使用 useCallback 作为我的 useFocus 自定义挂钩返回的函数。

我只想重新渲染焦点不断变化的组件。

我知道如果代码很快,重新渲染可能是个小问题,但我不明白为什么要重新渲染。 你能给我一些解释或修复吗?

预期结果

单击 'set focus' 按钮时,我希望得到:

1 渲染 A/B/D

2 呈现 C/E

谢谢。

这是我的代码:

import React, { createContext, useCallback, useContext, useState } from "react";
import "./styles.css";

const StepContext = createContext({});

//This is just to display number or render for each Items
function useRenderCounter() {
  const ref = React.useRef();
  React.useEffect(() => {
    ref.current.textContent = Number(ref.current.textContent || "0") + 1;
  });
  return (
    <span
      style={{
        backgroundColor: "#ccc",
        borderRadius: 4,
        padding: "2px 4px",
        fontSize: "0.8rem",
        margin: "0 6px",
        display: "inline-block"
      }}
      ref={ref}
    />
  );
}

const useFocus = (property) => {
  const context = useContext(StepContext);

  const bool = context === property;
  //console.log("bool", bool, context, property);

  //return bool
  return useCallback(() => bool, [bool]);
};

const Item = React.memo(({ property }) => {
  const rendercounter = useRenderCounter();
  const isFocus = useFocus(property);
  //Here I expect to got re-render only for property which the focus changed

  const focus = isFocus();

  console.log(property, "render", focus);

  const style = focus ? { borderStyle: "solid", borderColor: "red" } : {};

  return (
    <div style={{ display: "flex", margin: "4px" }}>
      {rendercounter}
      <div style={style}>{property}</div>
    </div>
  );
});

export default function App() {
  const [focusOn, setFocusOn] = useState("E");

  const handleClick = () => setFocusOn("C");

  return (
    <StepContext.Provider value={focusOn}>
      <div style={{ display: "flex", flexDirection: "column" }}>
        <Item key={1} property={"A"} />
        <Item key={2} property={"B"} />
        <Item key={3} property={"C"} />
        <Item key={4} property={"D"} />
        <Item key={5} property={"E"} />
        <button onClick={handleClick}>set focus</button>
      </div>
    </StepContext.Provider>
  );
}

Here the sandbox

Provider 获取新值时无法避免重新渲染。来自 official docs on Context API:

All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes. The propagation from Provider to its descendant consumers (including .contextType and useContext) is not subject to the shouldComponentUpdate method, so the consumer is updated even when an ancestor component skips an update.