Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add useRefState hooks #2348

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
24 changes: 24 additions & 0 deletions packages/hooks/src/useStateRef/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { renderHook, act } from '@testing-library/react';
import useStateRef from '../index';

describe('useRafState', () => {
it('should work', () => {
const mockRaf = jest
.spyOn(window, 'requestAnimationFrame')
.mockImplementation((cb: FrameRequestCallback) => {
cb(0);
return 0;
});
const { result } = renderHook(() => useStateRef(0));
liuyib marked this conversation as resolved.
Show resolved Hide resolved
const setStateRef = result.current[1];
expect(result.current[0]).toBe(0);
expect(result.current[2]()).toBe(0);

act(() => {
setStateRef(1);
});
expect(result.current[0]).toBe(1);
expect(result.current[2]()).toBe(1);
mockRaf.mockRestore();
});
});
liuyib marked this conversation as resolved.
Show resolved Hide resolved
30 changes: 30 additions & 0 deletions packages/hooks/src/useStateRef/demo/demo1.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* title: Basic usage
* desc: useSize can receive ref as argument
*
* title.zh-CN: 基础用法
* desc.zh-CN: useSize 可以接收 ref 参数
*/
liuyib marked this conversation as resolved.
Show resolved Hide resolved

import React, { useEffect } from 'react';
import { useStateRef } from 'ahooks';


export default () => {
const [value, setValue, getValue] = useStateRef(false);

useEffect(() => {
setTimeout(() => {
setValue('data loaded from server');
}, 5000);

setTimeout(() => {
console.log(getValue());
}, 6000);
maxiaokai1996 marked this conversation as resolved.
Show resolved Hide resolved
}, []);

const text = value || 'Loading...';

return <div>{text}</div>;
};

19 changes: 19 additions & 0 deletions packages/hooks/src/useStateRef/index.en-US.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
nav:
path: /hooks
---

# useStateRef
To deal with the closure problem, there is an additional function to get the latest state on the basis of useState
maxiaokai1996 marked this conversation as resolved.
Show resolved Hide resolved

## Examples

### Default usage

<code src="./demo/demo1.tsx" />

## API

```typescript
const [value, setValue, getValue] = useStateRef(false);
```
16 changes: 16 additions & 0 deletions packages/hooks/src/useStateRef/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useRef, useState, useCallback } from "react";
import { isFunction } from '../utils';

export default function useStateRef<T>(value?: T) {
const [state, setState] = useState(value);
liuyib marked this conversation as resolved.
Show resolved Hide resolved
const stateRef = useRef(state);

const setStateRef = useCallback((patch: T | ((state?: T) => T)) => {
const newState = isFunction(patch) ? patch(stateRef.current) : patch;
stateRef.current = newState;
setState(newState);
}, [])

const getState = useCallback(() => stateRef.current, []);
return [state, setStateRef, getState] as const;
}
19 changes: 19 additions & 0 deletions packages/hooks/src/useStateRef/index.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
nav:
path: /hooks
---

# useStateRef
处理闭包问题,在useState的基础上多了一个获取最新state的函数
maxiaokai1996 marked this conversation as resolved.
Show resolved Hide resolved

## 代码演示

### 基础用法

<code src="./demo/demo1.tsx" />

## API

```typescript
const [value, setValue, getValue] = useStateRef(false);
```
liuyib marked this conversation as resolved.
Show resolved Hide resolved