【问题标题】:How to overwrite React.Component state type from inherited class?如何从继承的类中覆盖 React.Component 状态类型?
【发布时间】:2019-12-16 15:38:12
【问题描述】:

我有一个扩展另一个组件的组件类,我正试图弄清楚如何覆盖我从中继承的状态的类型。

这是一个例子:

class MyComponent extends React.Component<SomeProps, SomeState> {
  // ...
}

class ExtendedComponent extends MyComponent {
  // How to overwrite SomeState?
  // This component needs to store a different model of state.
}

我需要ExtendedComponent 为其interface 使用不同的state,但我不知道如何实现这一点。


编辑:现在去某个地方!

但是,现在Parent 充满了与状态修改有关的各种错误。到目前为止,这是我所得到的:

interface ParentProps {
  a: string;
}

interface ParentState {
  b: string;
}

class Parent<P, S> extends React.Component<ParentProps & P, ParentState & S> {
  constructor(props) {
    super(props);

    // Type '{ b: "hello"; }' is not assignable to type 'Readonly<ParentState & S>'
    this.state = {
      b: 'hello',
    };
  }

  aFunction(): void {
    /*
      Argument of type '{ b: "testing"; }' is not assignable to parameter of type '(ParentState & S) | ((prevState: Readonly<ParentState & S>, props: Readonly<ParentProps & P>) => (ParentState & S) | Pick<ParentState & S, "b">) | Pick<ParentState & S, "b">'.
  Type '{ b: "testing"; }' is not assignable to type 'Pick<ParentState & S, "b">'.
    Types of property 'b' are incompatible.
      Type '"testing"' is not assignable to type 'string & S["b"]'.
        Type '"testing"' is not assignable to type 'S["b"]'.
    */
    this.setState({
      b: 'testing',
    });
  }
}

interface ChildProps {
  c: string;
}

interface ChildState {
  d: string;
}

class Child extends Parent<ChildProps, ChildState> {
  constructor(props) {
    super(props);

    // This is what I'm after -- and TypeScript doesn't complain :)
    this.state = {
      b: 'hello',
      d: 'world',
    };
  }
}

编辑 2:

近两年后回想起来:

由 React 的维护者扩展另一个组件类 is not recommended。这是有充分理由的,因为我必须在糟糕的生产应用程序中维护这种方法!我最终使用高阶组件和自定义钩子重写了很多代码。

这个用例没有得到很好的支持是有原因的,避免因过度设计组件而导致复杂化!想象一下,试图向另一位开发人员解释你纠结的继承问题。

仅仅因为它听起来很酷并且您可以做到,并不意味着您应该这样做。我强烈建议使用功能组件,如果您需要共享功能,请使用higher-order functions 和/或custom hooks

【问题讨论】:

  • 您最终找到解决方案了吗?
  • @Luze 不幸的是,没有。如果你发现了什么,请告诉我!

标签: reactjs typescript generics overwrite


【解决方案1】:

我猜你不想替换道具和状态,因为你可能需要一个通用接口来使父类工作。所以你可以让你的父类通用,然后合并额外的道具/状态。

class MyComponent<P, S> extends React.Component<ParentProps & P, ParentState & S> {}
//                ^ Generic P is for child props, Generic S is for child state

使用示例:

type ParentProps = { a: number }
type ParentState = { b: number }
class MyComponent<P, S> extends React.Component<ParentProps & P, ParentState & S> {}
let parentComponent = <MyComponent a={1} />

type ChildProps = { c: number }
type ChildState = { d: number }
class ExtendedComponent extends MyComponent<ChildProps, ChildState> {}
let childComponent = <ExtendedComponent a={1} c={2} />

【讨论】:

  • 感谢您的回答!终于到了某个地方:) 然而,现在MyComponent 类充满了关于传递给setState 的对象的错误,并且constructor 中的this.state = 声明与ParentState &amp; S 类型不兼容。我必须进行状态修改吗?查看更新的答案。
  • 我呃,不知道...你试过用钩子代替吗? :P
  • 不,这些类还有很多,使用功能组件对我来说不是一个选项。感谢您的帮助,我将对泛型做更多的研究,并将用任何发现更新帖子。 :)
【解决方案2】:

对于任何搜索此内容并陷入“EDIT 2”问题的人,一种解决方法是像这样在 setState() 调用中传播先前的状态。

this.setState(prevState => { return { ...prevState, foo: newFoo }});

这是必需的,这样无论 S 模板中的内容是什么,它都会被传播并且不会被覆盖(并且您还可以将扩展组件设为通用并从中继承等等)。

你也可以,如果你想在构造函数中设置状态,你可以这样做

super(props);
this.state = {
   ...this.state, 
   foo: newFoo
};

这样,在父类中初始化的状态将保持不变。如果您知道父状态的每个字段,也可以直接覆盖它。

【讨论】:

    猜你喜欢
    • 2012-10-15
    • 2016-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-30
    • 1970-01-01
    • 2014-11-21
    相关资源
    最近更新 更多