Bootstrap

在TypeScript中使用React钩子

目录

示例:typed useReducer ()

这太容易了吗?

测试自定义钩子


ReactTypeScript是构建更安全,更具伸缩性的Web应用程序的强大组合。

不幸的是,并非JavaScript社区采用的每种模式都很好地转换为TypeScript。例如,通过围绕新的动态创建的组件包含通用逻辑,实现更高阶的组件,从而实现代码重用。随时随地制作JavaScript哲学中受尊重的(如果不是预期的)原则,但动态创建的接口在编译时通常很难描述(如果不是不可能的话)。

输入钩子,一种替代的TypeScript友好模式,用于代码重用。他们已准备好插入您的其他类型安全的React应用程序,他们将尊重代码中的现有约束。只需更新reactreact-dom> = 16.8.0

$ npm i --save \
  [email protected] \
  [email protected]

我们也需要更新的typings。钩子定义latest出现在v16.7.0之后:

$ npm i --save \
  @types/[email protected] \
  @types/[email protected]

使用类型定义和工作的TypeScript配置,我们已准备好开始使用钩子。

示例:typed useReducer ()

让我们使用ReactuseReducer钩子重写经典的计数器示例。该reducer问题是完全一样的(由执行,签名和类型定义),你可能会在使用类型安全的终极版的应用程序

// reducer.ts
type Action = 'INCREMENT' | 'DECREMENT';

type State = {
  count: number;
};

const reducer = (state: State, action: Action) => {
  switch (action) {
    case 'INCREMENT':
      return {count: state.count + 1};
    case 'DECREMENT':
      if (state.count === 0) {
        return state;
      }
      return {count: state.count - 1};
    default:
      return state;
  }
};

export default reducer;

然而,ReactuseReducer()钩子现在接管了我们的状态容器,而不是中央的redux存储。

import * as React from 'react';
import reducer from './reducer';

const Counter: React.SFC<{}> = () => {
  const [state, dispatch] = React.useReducer(reducer, {count: 0});

  return (
    <div>
      <h1>Count: {state.count}</h1>
      <div>
        <button onClick={() => dispatch('INCREMENT')}>+1</button>
        <button onClick={() => dispatch('DECREMENT')}>-1</button>
      </div>
    </div>
  );
};

最好的部分?useReducer开箱即用的类型将推断出我们reducer的形状,并正确地提出明显的错误。尝试更改countstring-而不使用显式类型注释,TypeScript将正确地推断出state.count需要是 number

这太容易了吗?

因此,钩子可以很好地(非常好地)与静态类型应用程序的其余部分一起使用。不过,有几点需要注意。

  1. 编译器只知道它的内容。Hook 接口 是键入的,但它们的类型是简单的,通用的,并且是最低限度的规范。自定义钩子实现中发生了什么?那是我们的事。
  2. Hooks期望在React组件中运行。这在生产中是一个非问题,其中一切都发生在组件内部,但它确实使测试稍微复杂化。

测试自定义钩子

实际上,让我们尝试测试一个自定义钩子

const useCapitalized =
  (s: string): ReturnType<typeof React.useState> => {
    const [state, setState] = React.useState(s);
    return [state.toUpperCase(), setState];
  };

我们不会在实践中使用useCapitalized——toUpperCase()工作正常,谢谢你,不需要额外的样板——但它现在是一个有用的MacGuffin

为了测试它,我们就希望能够写类似以下内容:

test('sets initial state', () => {
  const [actual] = useCapitalized('Hello, world');
  expect(actual).toEqual('HELLO, WORLD');
}

但是这个测试本身还不够。为了使它通过测试,我们需要一个使钩子可以在里面运行的最小测试组件。添加它,我们的最终测试看起来像这样:

import * as React from 'react';
import * as TestRenderer from 'react-test-renderer';

// ...
const HelloWorld = () => {
  const [state] = useCapitalized('Hello, world');
  return <b>{state}</b>;
};

test('.useCapitalized', () => {
  const testRenderer = TestRenderer.create(<HelloWorld />);
  expect(testRenderer.toJSON()).toMatchSnapshot();
});

一点也不差,在测试工具复杂度的大方案中,判断结果如下:在易于集成和易于测试之间,React的钩子应该是TypeScript开发人员多年来的好朋友。

 

原文地址:https://www.codeproject.com/Articles/1277165/Using-React-Hooks-with-TypeScript

;