hooks icon indicating copy to clipboard operation
hooks copied to clipboard

feat: add useProState hook

Open coding-ice opened this issue 10 months ago • 5 comments

[中文版模板 / Chinese template]

🤔 This is a ...

  • [x] New feature
  • [ ] Bug fix
  • [x] Site / documentation update
  • [x] Demo update
  • [x] TypeScript definition update
  • [ ] Bundle size optimization
  • [ ] Performance optimization
  • [ ] Enhancement feature
  • [ ] Internationalization
  • [ ] Refactoring
  • [ ] Code style optimization
  • [ ] Test Case
  • [ ] Branch merge
  • [ ] Other (about what?)

🔗 Related issue link

close: https://github.com/alibaba/hooks/issues/2432

💡 Background and solution

📝 Changelog

Language Changelog
🇺🇸 English add useProState
🇨🇳 Chinese

☑️ Self Check before Merge

⚠️ Please check all items below before review. ⚠️

  • [x] Doc is updated/provided or not needed
  • [x] Demo is updated/provided or not needed
  • [x] TypeScript definition is updated/provided or not needed
  • [x] Changelog is provided or not needed

coding-ice avatar Apr 13 '24 13:04 coding-ice

这个往 v4 分支合

crazylxr avatar Apr 21 '24 08:04 crazylxr

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
5 out of 6 committers have signed the CLA.

:white_check_mark: guoyunhe
:white_check_mark: coding-ice
:white_check_mark: joe-leong
:white_check_mark: guaijie
:white_check_mark: LonelyFellas
:x: crazylxr
You have signed the CLA already but the status is still pending? Let us recheck it.

CLAassistant avatar Apr 21 '24 08:04 CLAassistant

都可以了,分支从master切的,没太注意,抱歉~

coding-ice avatar Apr 22 '24 10:04 coding-ice

目前的getState还是不能实时获取到期待的setState之后的值,见这个issues,https://github.com/alibaba/hooks/issues/2631
我这里改写setState,在setState之前获取要赋值的新值,塞给ref,这样ref就能同步获取到最新的值了, 大佬们看看这样是否可行,有什么隐患

import { useState, type Dispatch, type SetStateAction, useCallback, useRef } from 'react';
import { isFunction } from 'ahooks/es/utils';

export type SetMergeState<S extends Record<string, never>> = <K extends keyof S>(
  state: Pick<S, K> | null | ((prevState: Readonly<S>) => Pick<S, K> | S | null),
) => void;
export type DispatchType<S> = Dispatch<SetStateAction<S>>;

function useProState<S extends Record<string, never>>(
  initialState?: S | (() => S),
): [
  S,
  {
    setState: DispatchType<S>;
    getState: () => S;
    resetState: () => void;
    setMergeState: SetMergeState<S>;
  },
];

function useProState<S>(initialState?: S | (() => S)): [
  S,
  {
    setState: DispatchType<S>;
    getState: () => S;
    resetState: () => void;
    setMergeState: (s: Record<string, never>) => void;
  },
];

function useProState<S>(initialState: S) {
  const [state, setStatePrivate] = useState<S>(initialState);
  const currentStateRef = useRef(state);

  const setState = useCallback((patch: unknown) => {
    const newState = isFunction(patch) ? patch(state) : patch;
    setStatePrivate(newState);
    currentStateRef.current = newState;
  }, [state]);
  const getState = useCallback(() => currentStateRef.current, []);

  const resetState = useCallback(() => {
    setState(initialState);
  }, []);

   const setMergeState = useCallback((patch: unknown) => {
    const newState = isFunction(patch) ? patch(state) : patch;
    const result = newState ? { ...state, ...newState } : state;
    setStatePrivate(result);
    currentStateRef.current = result;
  }, [state]);

  return [state, { setState, getState, resetState, setMergeState }];
}

export default useProState;

pangao66 avatar Aug 25 '24 13:08 pangao66

目前的getState还是不能实时获取到期待的setState之后的值,见这个issues,#2631 我这里改写setState,在setState之前获取要赋值的新值,塞给ref,这样ref就能同步获取到最新的值了, 大佬们看看这样是否可行,有什么隐患

import { useState, type Dispatch, type SetStateAction, useCallback, useRef } from 'react';
import { isFunction } from 'ahooks/es/utils';

export type SetMergeState<S extends Record<string, never>> = <K extends keyof S>(
  state: Pick<S, K> | null | ((prevState: Readonly<S>) => Pick<S, K> | S | null),
) => void;
export type DispatchType<S> = Dispatch<SetStateAction<S>>;

function useProState<S extends Record<string, never>>(
  initialState?: S | (() => S),
): [
  S,
  {
    setState: DispatchType<S>;
    getState: () => S;
    resetState: () => void;
    setMergeState: SetMergeState<S>;
  },
];

function useProState<S>(initialState?: S | (() => S)): [
  S,
  {
    setState: DispatchType<S>;
    getState: () => S;
    resetState: () => void;
    setMergeState: (s: Record<string, never>) => void;
  },
];

function useProState<S>(initialState: S) {
  const [state, setStatePrivate] = useState<S>(initialState);
  const currentStateRef = useRef(state);

  const setState = useCallback((patch: unknown) => {
    const newState = isFunction(patch) ? patch(state) : patch;
    setStatePrivate(newState);
    currentStateRef.current = newState;
  }, [state]);
  const getState = useCallback(() => currentStateRef.current, []);

  const resetState = useCallback(() => {
    setState(initialState);
  }, []);

   const setMergeState = useCallback((patch: unknown) => {
    const newState = isFunction(patch) ? patch(state) : patch;
    const result = newState ? { ...state, ...newState } : state;
    setStatePrivate(result);
    currentStateRef.current = result;
  }, [state]);

  return [state, { setState, getState, resetState, setMergeState }];
}

export default useProState;

可以考虑一下, @coding-ice 你看看呢,获取最新值的问题

crazylxr avatar Aug 29 '24 01:08 crazylxr