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(useGetState): get state synchronously #2268

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/hooks/src/useGetState/demo/demo1.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ export default () => {
};
}, []);

return <button onClick={() => setCount((count) => count + 1)}>count: {count}</button>;
return <button onClick={() => setCount((prevCount) => prevCount + 1)}>count: {count}</button>;
};
liuyib marked this conversation as resolved.
Show resolved Hide resolved
20 changes: 13 additions & 7 deletions packages/hooks/src/useGetState/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import type { Dispatch, SetStateAction } from 'react';
import type { Dispatch } from 'react';
import { useState, useRef, useCallback } from 'react';
import { isFunction } from '../utils';

type SetStateAction<S> = Dispatch<React.SetStateAction<S>>;
type GetStateAction<S> = () => S;

function useGetState<S>(
initialState: S | (() => S),
): [S, Dispatch<SetStateAction<S>>, GetStateAction<S>];
function useGetState<S>(initialState: S | (() => S)): [S, SetStateAction<S>, GetStateAction<S>];
function useGetState<S = undefined>(): [
S | undefined,
Dispatch<SetStateAction<S | undefined>>,
SetStateAction<S | undefined>,
GetStateAction<S | undefined>,
];
function useGetState<S>(initialState?: S) {
const [state, setState] = useState(initialState);
const [state, setInnerState] = useState(initialState);
const stateRef = useRef(state);
stateRef.current = state;

const setState = useCallback<SetStateAction<S | undefined>>((stateOrAction) => {
const newState = isFunction(stateOrAction) ? stateOrAction(stateRef.current) : stateOrAction;

stateRef.current = newState;
setInnerState(newState);
Copy link
Collaborator

@hchlq hchlq Aug 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同步后,要补个单测吗

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以,我补下

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

程哥,看下这个讨论:#2266 (comment), 这个 PR 的改动, 之前就有人提过 #1306 (comment), 不知道现在这个改动算不算破坏性更改呢?之前是没法通过 getState 同步获取到最新状态的, 应该不会有人还用它来获取旧状态吧 #2266 (comment)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有可能的,刚才有想到过,不过一般使用的人都是在 render 过程中的,像在 set 之后重新获取旧状态的比较少。

不过咱们还是保险起见,放到 v4 的规划是不是更好呢

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有可能的,刚才有想到过,不过一般使用的人都是在 render 过程中的,像在 set 之后重新获取旧状态的比较少。

不过咱们还是保险起见,放到 v4 的规划是不是更好呢

好的呢,那就放在 v4 做吧~

}, []);

const getState = useCallback(() => stateRef.current, []);

Expand Down
Loading