Repository: alibaba/hooks
Pull request #1065 (2021-07-26 11:22:41)

refactor: usePrevious

brickspert: fix: #918 #780 

Patch:
diff --git a/packages/hooks/src/useCreation/index.en-US.md b/packages/hooks/src/useCreation/index.en-US.md
index 9495de52..e9fdf299 100644
--- a/packages/hooks/src/useCreation/index.en-US.md
+++ b/packages/hooks/src/useCreation/index.en-US.md
@@ -6,11 +6,12 @@ nav:
 group:
   title: Advanced
   path: /advanced
-  order: 15
 ---
 
 # useCreation
 
+<Tag lang="en-US" tags="ssr&crossPlatform"></Tag>
+
 `useCreation` is the replacement for `useMemo` or `useRef`.
 
 `useMemo` can't guarantee the memoized value will not be recalculated, while `useCreation` can guarantee that. As the the official document of React.js says:
@@ -38,8 +39,8 @@ function useCreation<T>(factory: () => T, deps: any[]): T;
 
 ### Params
 
-| Property | Description                              | Type      | Default |
-|----------|------------------------------------------|-----------|---------|
+| Property | Description                              | Type        | Default |
+|----------|------------------------------------------|-------------|---------|
 | factory  | A function used for creating the object. | `() => any` | -       |
 | deps     | The dependencies list.                   | `any[]`     | -       |
 
diff --git a/packages/hooks/src/useCreation/index.zh-CN.md b/packages/hooks/src/useCreation/index.zh-CN.md
index 972dd18e..39e6d018 100644
--- a/packages/hooks/src/useCreation/index.zh-CN.md
+++ b/packages/hooks/src/useCreation/index.zh-CN.md
@@ -6,11 +6,12 @@ nav:
 group:
   title: Advanced
   path: /advanced
-  order: 15
 ---
 
 # useCreation
 
+<Tag lang="zh-CN" tags="ssr&crossPlatform"></Tag>
+
 `useCreation` 是 `useMemo` 或 `useRef` 的替代品。
 
 因为 `useMemo` 不能保证被 memo 的值一定不会被重计算，而 `useCreation` 可以保证这一点。以下为 React 官方文档中的介绍：
@@ -38,8 +39,8 @@ function useCreation<T>(factory: () => T, deps: any[]): T;
 
 ### Params
 
-| 参数    | 说明                   | 类型      | 默认值 |
-|---------|------------------------|-----------|--------|
+| 参数    | 说明                   | 类型        | 默认值 |
+|---------|------------------------|-------------|--------|
 | factory | 用来创建所需对象的函数 | `() => any` | -      |
 | deps    | 传入依赖变化的对象     | `any[]`     | -      |
 
diff --git a/packages/hooks/src/useEventEmitter/index.en-US.md b/packages/hooks/src/useEventEmitter/index.en-US.md
index b88193a1..9ca1b7c8 100644
--- a/packages/hooks/src/useEventEmitter/index.en-US.md
+++ b/packages/hooks/src/useEventEmitter/index.en-US.md
@@ -6,11 +6,12 @@ nav:
 group:
   title: Advanced
   path: /advanced
-legacy: /advanced/use-event-emitter
 ---
 
 # useEventEmitter
 
+<Tag lang="en-US" tags="ssr&crossPlatform"></Tag>
+
 Sometimes it is difficult to pass events between multiple components. By using EventEmitter, this can be simplified.
 
 To get an instance of `EventEmitter`, you can call `useEventEmitter` in React components.
diff --git a/packages/hooks/src/useEventEmitter/index.ts b/packages/hooks/src/useEventEmitter/index.ts
index 986efa89..0b6a801b 100644
--- a/packages/hooks/src/useEventEmitter/index.ts
+++ b/packages/hooks/src/useEventEmitter/index.ts
@@ -12,8 +12,10 @@ export class EventEmitter<T> {
   };
 
   useSubscription = (callback: Subscription<T>) => {
+    // eslint-disable-next-line react-hooks/rules-of-hooks
     const callbackRef = useRef<Subscription<T>>();
     callbackRef.current = callback;
+    // eslint-disable-next-line react-hooks/rules-of-hooks
     useEffect(() => {
       function subscription(val: T) {
         if (callbackRef.current) {
diff --git a/packages/hooks/src/useEventEmitter/index.zh-CN.md b/packages/hooks/src/useEventEmitter/index.zh-CN.md
index f21f856c..3bfd544d 100644
--- a/packages/hooks/src/useEventEmitter/index.zh-CN.md
+++ b/packages/hooks/src/useEventEmitter/index.zh-CN.md
@@ -6,11 +6,12 @@ nav:
 group:
   title: Advanced
   path: /advanced
-legacy: /zh-CN/advanced/use-event-emitter
 ---
 
 # useEventEmitter
 
+<Tag lang="zh-CN" tags="ssr&crossPlatform"></Tag>
+
 在多个组件之间进行事件通知有时会让人非常头疼，借助 EventEmitter ，可以让这一过程变得更加简单。
 
 在组件中调用 `useEventEmitter` 可以获得一个 `EventEmitter` 的实例：
diff --git a/packages/hooks/src/useLockFn/demo/demo1.tsx b/packages/hooks/src/useLockFn/demo/demo1.tsx
index 0978f18a..980cc87c 100644
--- a/packages/hooks/src/useLockFn/demo/demo1.tsx
+++ b/packages/hooks/src/useLockFn/demo/demo1.tsx
@@ -6,9 +6,9 @@
  * desc.zh-CN: 在 `submit` 函数执行完成前，其余的点击动作都会被忽略。
  */
 
-import React, { useState } from 'react';
-import { message } from 'antd';
 import { useLockFn } from 'ahooks';
+import { message } from 'antd';
+import React, { useState } from 'react';
 
 function mockApiRequest() {
   return new Promise((resolve) => {
diff --git a/packages/hooks/src/useLockFn/index.en-US.md b/packages/hooks/src/useLockFn/index.en-US.md
index f894cded..46e25ffc 100644
--- a/packages/hooks/src/useLockFn/index.en-US.md
+++ b/packages/hooks/src/useLockFn/index.en-US.md
@@ -10,11 +10,13 @@ group:
 
 # useLockFn
 
+<Tag lang="en-US" tags="ssr&crossPlatform"></Tag>
+
 Add lock to an async function to prevent parallel executions.
 
 ## Examples
 
-### Prevent duplicated submits
+### Basic usage
 
 <code src="./demo/demo1.tsx" />
 
@@ -28,13 +30,13 @@ function useLockFn<P extends any[] = any[], V extends any = any>(
 
 ### Result
 
-| 参数 | 说明                      | 类型                      |
-|------|---------------------------|---------------------------|
-| fn   | The async function with lock | `(...args: any[]) => any` |
+| 参数 | 说明                         | 类型                               |
+|------|------------------------------|------------------------------------|
+| fn   | The async function with lock | `(...args: any[]) => Promise<any>` |
 
 ### Params
 
-| 参数           | 说明             | 类型                      | 默认值 |
-|----------------|------------------|---------------------------|--------|
-| fn             | An async function | `(...args: any[]) => any` | -      |
+| 参数 | 说明              | 类型                               | 默认值 |
+|------|-------------------|------------------------------------|--------|
+| fn   | An async function | `(...args: any[]) => Promise<any>` | -      |
 
diff --git a/packages/hooks/src/useLockFn/index.zh-CN.md b/packages/hooks/src/useLockFn/index.zh-CN.md
index 0320a6ba..5eff9c27 100644
--- a/packages/hooks/src/useLockFn/index.zh-CN.md
+++ b/packages/hooks/src/useLockFn/index.zh-CN.md
@@ -10,11 +10,13 @@ group:
 
 # useLockFn
 
+<Tag lang="zh-CN" tags="ssr&crossPlatform"></Tag>
+
 用于给一个异步函数增加竞态锁，防止并发执行。
 
 ## 代码演示
 
-### 避免重复提交
+### 基础用法
 
 <code src="./demo/demo1.tsx" />
 
@@ -28,13 +30,13 @@ function useLockFn<P extends any[] = any[], V extends any = any>(
 
 ### Result
 
-| 参数 | 说明                      | 类型                      |
-|------|---------------------------|---------------------------|
-| fn   | 增加了竞态锁的函数 | `(...args: any[]) => any` |
+| 参数 | 说明               | 类型                               |
+|------|--------------------|------------------------------------|
+| fn   | 增加了竞态锁的函数 | `(...args: any[]) => Promise<any>` |
 
 ### Params
 
-| 参数           | 说明             | 类型                      | 默认值 |
-|----------------|------------------|---------------------------|--------|
-| fn             | 需要增加竞态锁的函数 | `(...args: any[]) => any` | -      |
+| 参数 | 说明                 | 类型                               | 默认值 |
+|------|----------------------|------------------------------------|--------|
+| fn   | 需要增加竞态锁的函数 | `(...args: any[]) => Promise<any>` | -      |
 
diff --git a/packages/hooks/src/usePrevious/demo/demo2.tsx b/packages/hooks/src/usePrevious/demo/demo2.tsx
index a075c91a..591064d9 100644
--- a/packages/hooks/src/usePrevious/demo/demo2.tsx
+++ b/packages/hooks/src/usePrevious/demo/demo2.tsx
@@ -1,9 +1,9 @@
 /**
- * title: Using compare function
- * desc: The stored previous value update only when the compare function returns true.
+ * title: Custom shouldUpadte function
+ * desc: The stored previous value update only when the shouldUpadte function returns true.
  *
- * title.zh-CN: 使用 compare function
- * desc.zh-CN: 只有 compare function 返回 true 时，才会记录值的变化
+ * title.zh-CN: 自定义 shouldUpadte function
+ * desc.zh-CN: 只有 shouldUpadte function 返回 true 时，才会记录值的变化。
  */
 
 import React, { useState } from 'react';
diff --git a/packages/hooks/src/usePrevious/index.en-US.md b/packages/hooks/src/usePrevious/index.en-US.md
index 030f4492..9807e201 100644
--- a/packages/hooks/src/usePrevious/index.en-US.md
+++ b/packages/hooks/src/usePrevious/index.en-US.md
@@ -10,8 +10,9 @@ group:
 
 # usePrevious
 
-A Hook to store the previous value.
+<Tag lang="en-US" tags="ssr&crossPlatform"></Tag>
 
+A Hook to store the previous value.
 
 ## Examples
 
@@ -19,7 +20,7 @@ A Hook to store the previous value.
 
 <code src="./demo/demo1.tsx" />
 
-### Using compare function
+### Custom shouldUpadte function
 
 <code src="./demo/demo2.tsx" />
 
@@ -28,19 +29,19 @@ A Hook to store the previous value.
 ```typescript
 const previousState: T = usePrevious<T>(
   state: T,
-  compareFunction: (prev: T | undefined, next: T) => boolean
+  shouldUpdate?: (prev: T | undefined, next: T) => boolean
 );
 ```
 
 ### Result
 
-| Property      | Description        | Type |
-|---------------|--------------------|------|
-| previousState | the previous value | -    |
+| Property      | Description        | Type  |
+|---------------|--------------------|-------|
+| previousState | The previous value | `any` |
 
 ### Params
 
-| Property        | Description                                                   | Type | Default |
-|-----------------|---------------------------------------------------------------|------|---------|
-| state           | the state need to be tracked                                  | -    | -       |
-| compareFunction | optional, customize when the previous value need to be stored |  (prev: T \| undefined, next: T) => boolean    | -       |
+| Property     | Description                                                   | Type                                         | Default             |
+|--------------|---------------------------------------------------------------|----------------------------------------------|---------------------|
+| state        | The state need to be tracked                                  | `any`                                        | -                   |
+| shouldUpdate | Optional, customize when the previous value need to be stored | `(prev: T \| undefined, next: T) => boolean` | `(a, b) => a !== b` |
diff --git a/packages/hooks/src/usePrevious/index.ts b/packages/hooks/src/usePrevious/index.ts
index 3a446ab9..25ece104 100644
--- a/packages/hooks/src/usePrevious/index.ts
+++ b/packages/hooks/src/usePrevious/index.ts
@@ -1,13 +1,17 @@
 import { useRef } from 'react';
 
-export type compareFunction<T> = (prev: T | undefined, next: T) => boolean;
+export type ShouldUpdateFunc<T> = (prev: T | undefined, next: T) => boolean;
 
-function usePrevious<T>(state: T, compare?: compareFunction<T>): T | undefined {
+const defaultShouldUpdate = <T>(a?: T, b?: T) => a !== b;
+
+function usePrevious<T>(
+  state: T,
+  shouldUpdate: ShouldUpdateFunc<T> = defaultShouldUpdate,
+): T | undefined {
   const prevRef = useRef<T>();
   const curRef = useRef<T>();
 
-  const needUpdate = typeof compare === 'function' ? compare(curRef.current, state) : true;
-  if (needUpdate) {
+  if (shouldUpdate(curRef.current, state)) {
     prevRef.current = curRef.current;
     curRef.current = state;
   }
diff --git a/packages/hooks/src/usePrevious/index.zh-CN.md b/packages/hooks/src/usePrevious/index.zh-CN.md
index a086bc74..3ec2735f 100644
--- a/packages/hooks/src/usePrevious/index.zh-CN.md
+++ b/packages/hooks/src/usePrevious/index.zh-CN.md
@@ -10,8 +10,9 @@ group:
 
 # usePrevious
 
-保存上一次渲染时状态的 Hook。
+<Tag lang="zh-CN" tags="ssr&crossPlatform"></Tag>
 
+保存上一次状态的 Hook。
 
 ## 代码演示
 
@@ -19,7 +20,7 @@ group:
 
 <code src="./demo/demo1.tsx" />
 
-### 使用 compare function
+### 自定义 shouldUpadte function
 
 <code src="./demo/demo2.tsx" />
 
@@ -28,19 +29,19 @@ group:
 ```typescript
 const previousState: T = usePrevious<T>(
   state: T,
-  compareFunction: (prev: T | undefined, next: T) => boolean
+  shouldUpdate?: (prev: T | undefined, next: T) => boolean
 );
 ```
 
 ### Result
 
-| 参数          | 说明            | 类型 |
-|---------------|-----------------|------|
-| previousState | 上次 state 的值 | -    |
+| 参数          | 说明            | 类型  |
+|---------------|-----------------|-------|
+| previousState | 上次 state 的值 | `any` |
 
 ### Params
 
-| 参数            | 说明                     | 类型 | 默认值 |
-|-----------------|--------------------------|------|--------|
-| state           | 需要记录变化的值         | -    | -      |
-| compareFunction | 可选，自定义值变化的规则 |   (prev: T \| undefined, next: T) => boolean   | -      |
+| 参数         | 说明                       | 类型                                         | 默认值              |
+|--------------|----------------------------|----------------------------------------------|---------------------|
+| state        | 需要记录变化的值           | `any`                                        | -                   |
+| shouldUpdate | 可选，自定义判断值是否变化 | `(prev: T \| undefined, next: T) => boolean` | `(a, b) => a !== b` |
diff --git a/packages/hooks/src/useSafeState/demo/demo1.tsx b/packages/hooks/src/useSafeState/demo/demo1.tsx
index cd4b3fe6..eb91ce54 100644
--- a/packages/hooks/src/useSafeState/demo/demo1.tsx
+++ b/packages/hooks/src/useSafeState/demo/demo1.tsx
@@ -4,32 +4,25 @@
  * title.zh-CN: 基础用法
  */
 
-import React, { useState } from 'react';
-import useSafeState from '../index';
-
+import { useSafeState } from 'ahooks';
+import React, { useEffect, useState } from 'react';
 
 const Child = () => {
+  const [value, setValue] = useSafeState<string>();
 
-  const [value, setValue] = useSafeState<string>()
-  React.useEffect(() => {
+  useEffect(() => {
     setTimeout(() => {
-      setValue('从服务端获取的数据')
-    }, 5000)
-  }, [])
-
-  const text = value || '正在获取数据。。。'
+      setValue('从服务端获取的数据');
+    }, 5000);
+  }, []);
 
-  return (
-    <div>{text}</div>
-  )
-}
+  const text = value || '正在获取数据。。。';
 
+  return <div>{text}</div>;
+};
 
 export default () => {
-  
-
-  const [visible, setVisible] = useSafeState(true);
-
+  const [visible, setVisible] = useState(true);
 
   return (
     <div>
diff --git a/packages/hooks/src/useSafeState/index.en-US.md b/packages/hooks/src/useSafeState/index.en-US.md
index fae0e7fc..49943335 100644
--- a/packages/hooks/src/useSafeState/index.en-US.md
+++ b/packages/hooks/src/useSafeState/index.en-US.md
@@ -9,12 +9,15 @@ group:
 ---
 
 # useSafeState
-It is exactly the same with React.useState , but after the component is unloaded, the setstate in the asynchronous callback is no longer executed to avoid memory leakage caused by updating the state after the component is unloaded
 
+<Tag lang="en-US" tags="ssr&crossPlatform"></Tag>
+
+It is exactly the same with useState, but after the component is unloaded, the setstate is no longer executed to avoid memory leakage caused by updating the state after the component is unloaded.
 
 
 ## Examples
 
+### Basic usage
 
 <code src="./demo/demo1.tsx" />
 
diff --git a/packages/hooks/src/useSafeState/index.ts b/packages/hooks/src/useSafeState/index.ts
index 6194d451..cc04af3e 100644
--- a/packages/hooks/src/useSafeState/index.ts
+++ b/packages/hooks/src/useSafeState/index.ts
@@ -1,15 +1,16 @@
-import React, { Dispatch, SetStateAction } from 'react';
+import { useCallback, useState } from 'react';
+import type { Dispatch, SetStateAction } from 'react';
 import useUnmountedRef from '../useUnmountedRef';
 
 function useSafeState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
 
 function useSafeState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];
 
-function useSafeState(initialState?) {
+function useSafeState<S>(initialState?: S | (() => S)) {
   const unmountedRef = useUnmountedRef();
-  const [state, setState] = React.useState(initialState);
-  const setCurrentState = React.useCallback((currentState) => {
-    /** 如果组件已经卸载则不再更新 state */
+  const [state, setState] = useState(initialState);
+  const setCurrentState = useCallback((currentState) => {
+    /** if component is unmounted, stop update */
     if (unmountedRef.current) return;
     setState(currentState);
   }, []);
diff --git a/packages/hooks/src/useSafeState/index.zh-CN.md b/packages/hooks/src/useSafeState/index.zh-CN.md
index 0722e812..7b1e1f9f 100644
--- a/packages/hooks/src/useSafeState/index.zh-CN.md
+++ b/packages/hooks/src/useSafeState/index.zh-CN.md
@@ -9,11 +9,14 @@ group:
 ---
 
 # useSafeState
-用法与 React.useState 完全一样，但是在组件卸载后异步回调内的 setState 不再执行，避免因组件卸载后更新状态而导致的内存泄漏
+
+<Tag lang="zh-CN" tags="ssr&crossPlatform"></Tag>
+
+用法与 useState 完全一样，但是在组件卸载后 setState 不再执行，避免因组件卸载后更新状态而导致的内存泄漏。
 
 ## 代码演示
 
-### 基础用法，与 React.useState 完全一样
+### 基础用法
 
 <code src="./demo/demo1.tsx" />
 


Test patch:
diff --git a/packages/hooks/src/usePrevious/__tests__/index.test.ts b/packages/hooks/src/usePrevious/__tests__/index.test.ts
index 8f8d88e7..92ef6993 100644
--- a/packages/hooks/src/usePrevious/__tests__/index.test.ts
+++ b/packages/hooks/src/usePrevious/__tests__/index.test.ts
@@ -1,17 +1,17 @@
 import { renderHook } from '@testing-library/react-hooks';
-import usePrevious, { compareFunction as comFunc } from '../';
+import usePrevious, { ShouldUpdateFunc } from '../';
 
 describe('usePrevious', () => {
   it('should be defined', () => {
     expect(usePrevious).toBeDefined();
   });
 
-  function getHook<T>(initialValue?: T, compareFunction?: comFunc<T>) {
+  function getHook<T>(initialValue?: T, compareFunction?: ShouldUpdateFunc<T>) {
     return renderHook(({ val, cmp }) => usePrevious<T>(val as T, cmp), {
       initialProps: {
         val: initialValue || 0,
         cmp: compareFunction,
-      } as { val?: T; cmp?: comFunc<T> },
+      } as { val?: T; cmp?: ShouldUpdateFunc<T> },
     });
   }