React 类组件及函数组件结合Lodash debounce需要注意的问题和一种解决方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React 类组件及函数组件结合Lodash debounce需要注意的问题和一种解决方法相关的知识,希望对你有一定的参考价值。

参考技术A

在React组件中使用Lodash debounce函数,可能会出现防抖不生效的情况。
导致这个问题的主要原因:重新render导致debounce函数第一个参数是 新生成 的,而不是对同一个函数的引用
需要注意的就是debounce接收的第一个函数参数在不同的render周期内不是重新生成的,引用保持不变。

输入 lodash 函数的正确方法是啥?

【中文标题】输入 lodash 函数的正确方法是啥?【英文标题】:What is the proper way to type lodash functions?输入 lodash 函数的正确方法是什么? 【发布时间】:2019-05-07 22:08:07 【问题描述】:

我很难为使用 lodash 方法通过选择器连接到 redux 存储的 React 组件编写正确的类型。

在this article's conventions 之后,我的组件的简化版本如下所示

reducers/index.ts

interface ApiState 
  api: 
    entities: 
      subscriptions: 
        [pk: number]: 
          imageUrl: string;
          pk: number;
          slug: string;
          title: string;
        ;
      ;
    ;
    result: 
      subscriptions: never[];
    ;
  ;
  …
;

export type RootState =
  | (ApiState &
      FirebaseState & 
        router: Reducer<RouterState, LocationChangeAction>;
      )
  | ;

src/components/MyComponent.tsx

import React, PureComponent from "react";
import connect from "react-redux";
import RootState from "~/reducers";

interface OwnProps 
  label: "host" | "experience";
  score: number;
  subscriptionPk: number;

interface StateProps 
  subscription?: 
    pk: number;
    title: string;
  ;


const selectSubscriptions = state => state.api.entities.subscriptions;


const mapStateToProps = (state: RootState, ownProps: OwnProps): StateProps => (
  subscription: _.find(selectSubscriptions(state), 
    pk: ownProps.subscriptionPk,
  ) as any,
);

type Props = StateProps & OwnProps;

export default connect<StateProps, , OwnProps>(mapStateToProps)(
  class extends PureComponent<Props> 
    render() 
      const label, score, subscription = this.props;

      return (
        <div>
          label score subscription.title
        </div>
      );
    
  ,
);

src/typings.d.ts

// lodash global typing - begin
declare namespace _  // eslint-disable-line no-unused-vars
// lodash global typing - end

上面的代码在 lodash find 方法被转换为 any 之前工作:subscription: _.find() as any, in mapStateToProp。

如果我删除 as any,我会收到以下错误:

$ tsc --project tsconfig.json
src/components/MyComponent.tsx:37:3 - error TS2322: Type ' pk:  toString: ...; toFixed: ...; toExponential: ...; toPrecision: ...; valueOf: ...; toLocaleString: ...; [Symbol.iterator]: ...; ;  | undefined' is not assignable to type ' pk: number; slug: string; title: string;  | undefined'.
  Type ' pk:  toString: ...; toFixed: ...; toExponential: ...; toPrecision: ...; valueOf: ...; toLocaleString: ...; [Symbol.iterator]: ...; ; ' is missing the following properties from type ' pk: number; slug: string; title: string; ': slug, title

37   subscription: _.find(selectSubscriptions(state), 
     ~~~~~~~~~~~~

  src/components/MyComponent.tsx:26:3
    26   subscription?: 
         ~~~~~~~~~~~~
    The expected type comes from property 'subscription' which is declared here on type 'StateProps'


Found 1 error.

为什么 lodash 不能正确识别类型?我宁愿不必将所有 lodash 调用都转换为 any...

使用的版本:

反应 16.6.3 redux 4.0.1 react-redux 5.1.1 lodash-webpack-plugin 0.11.5(本身使用 lodash ^4.17.4) @types/lodash 4.14.119

【问题讨论】:

【参考方案1】:

只是不要提供泛型类型来不必要地连接。

在这里

import _ from "lodash";
import  PureComponent  from "react";
import React from "react";
import  connect  from "react-redux";

interface IApiState 
  api: 
    entities: 
      subscriptions: 
        [pk: number]: 
          imageUrl: string;
          pk: number;
          slug: string;
          title: string;
        ;
      ;
    ;
    result: 
      subscriptions: never[];
    ;
  ;


export type RootState = IApiState;

interface IOwnProps 
  label: "host" | "experience";
  score: number;
  subscriptionPk: number;

interface ISubscription 
  pk: number;
  title: string;

interface IStateProps 
  subscription?: ISubscription;


const selectSubscriptions = (state: RootState) =>
  state.api.entities.subscriptions;

const mapStateToProps = (
  state: RootState,
  ownProps: IOwnProps,
) => (
  subscription: _.find(selectSubscriptions(state), 
    pk: ownProps.subscriptionPk,
  ),
);

type Props = IStateProps & IOwnProps;

export default connect(mapStateToProps)(
  class extends PureComponent<Props> 
    public render() 
      const  label, score, subscription  = this.props;

      return (
        <div>
          label score subscription && subscription.title
        </div>
      );
    
  ,
);

【讨论】:

感谢您的回复!我尝试更改_.find() as any_.find()connect&lt;StateProps, , OwnProps&gt;connect,但_find 行上的错误仍然存​​在。这似乎不是解决方案。此外,我发现 connect 泛型类型声明对于理解它通常期望的内容非常有用。 您的示例还提示了一个不相关的问题。老实说,我还不清楚类型和接口之间的区别,在我目前的使用情况下,它看起来几乎是一样的(接口更灵活一些)。因此,我想知道为什么有几个人使用这个 I 前缀命名约定来区分接口和类型。只是偏好/习惯的问题,还是背后有更严重的原因? 我在我的一个解决方案上尝试了这个,并且我使用了一个要求 I 在接口名称之前的 linter,这只是一个约定。但是,就像我说的那样,我试过了,它奏效了。那么如果有可能你可以创建一个 git repo 吗?

以上是关于React 类组件及函数组件结合Lodash debounce需要注意的问题和一种解决方法的主要内容,如果未能解决你的问题,请参考以下文章

react函数式组件及类式组件

输入 lodash 函数的正确方法是啥?

JS每日一题: react中类组件和函数式组件中有什么不同?

使用 lodash.debounce 延迟测试组件失败

从0到1教你学会 react

React概述JSX语法及React组件