【问题标题】:Listen to changes in a value inside an object in React context在 React 上下文中监听对象内部值的变化
【发布时间】:2022-01-13 07:30:31
【问题描述】:

给定以下 React Context Provider。一个简单的 Counter 类,有 2 个方法,存储在 React 上下文中。

import { createContext, useContext } from "react";

class Counter {
  public count: number = 0;

  getCount = () => {
    return this.count;
  };

  incrementCount = () => {
    this.count = this.count + 1;
  };
}

type CounterContextType = {
  counter: Counter;
};

const defaults: CounterContextType = {
  counter: new Counter()
};

const CounterContext = createContext<CounterContextType>(defaults);

export const CounterProvider: React.FC = ({ children }) => {
  const counter = new Counter();

  return (
    <CounterContext.Provider
      value={{
        counter
      }}
    >
      {children}
    </CounterContext.Provider>
  );
};

export const useCounter = () => {
  return useContext(CounterContext);
};

我想监听Counter 实例的count 属性的变化。

这是我尝试过的:

import { useMemo } from "react";
import { CounterProvider, useCounter } from "./CounterProvider";

const DisplayWithMethod = () => {
  const { counter } = useCounter();

  return <div>Method: {counter.getCount()}</div>;
};

const DisplayWithProperty = () => {
  const { counter } = useCounter();

  return <div>Prop: {counter.count}</div>;
};

const DisplayWithMemo = () => {
  const { counter } = useCounter();

  const val = useMemo(() => counter.count, [counter.count]);

  return <div>Memo: {val}</div>;
};

const Button = () => {
  const { counter } = useCounter();

  return <button onClick={counter.incrementCount}>Increment</button>;
};

export default function App() {
  return (
    <CounterProvider>
      <DisplayWithMethod />
      <DisplayWithProperty />
      <DisplayWithMemo />
      <Button />
    </CounterProvider>
  );
}

这些都不起作用,因为计数器实例永远不会改变,因此不会触发重新渲染。关于如何在保持Counter 的类结构的同时完成这项工作的任何想法。

https://codesandbox.io/s/nostalgic-fast-cyflg

【问题讨论】:

  • 你好,我假设你给出了一个非常简单的复制。我的建议是,让您的 Counter 类 可订阅,使用 forceUpdate 函数订阅(从 useState 或 useReducer 获取)。所以当你的 Counter 更新一个值时,它会触发订阅者并强制响应重新渲染

标签: javascript reactjs typescript


【解决方案1】:

问题在于 React 没有得到计数已经改变并且没有重新渲染。你可以使用useState hook 来解​​决这个问题。

您应该像下面这样更改类型定义并使用 useState 钩子的输出构造计数器实例。

import { createContext, useContext, useState } from "react";

type CounterContextType = {
  counter: {
    count: number;
    getCount: () => number;
    incrementCount: () => void;
  };
};

const defaults: CounterContextType = {
  counter: {
    count: 0,
    getCount: () => 0,
    incrementCount: () => undefined
  }
};

const CounterContext = createContext<CounterContextType>(defaults);

export const CounterProvider: React.FC = ({ children }) => {
  const [count, setCount] = useState<number>(0);

  return (
    <CounterContext.Provider
      value={{
        counter: {
          count,
          getCount: () => count,
          incrementCount: () => {
            setCount((prevCount) => prevCount + 1);
          }
        }
      }}
    >
      {children}
    </CounterContext.Provider>
  );
};

export const useCounter = () => {
  return useContext(CounterContext);
};

Code Sandbox

【讨论】:

  • @klugjo,看看这个!!
  • 没有理由将counter: {} 嵌套在value
  • 我同意这是这个简单示例的正确方法。但是我真的需要直接重用Counter这个类,不能改。试想Counter里面有几千行代码,如果我改成用你的模式,不可行
猜你喜欢
  • 2011-10-05
  • 1970-01-01
  • 2019-11-01
  • 2021-12-12
  • 2017-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多