簡體   English   中英

如何使用 redux state 更新反應 HOC 組件?

[英]How to update react HOC component with redux state?

下面是 HOC,它也連接到 redux 商店。 WrappedComponent function 在 storedata 更改時未獲取 redux state。 這里有什么問題?

export function withCreateHOC<ChildProps>(
  ChildComponent: ComponentType,
  options: WithCreateButtonHOCOptions = {
    title: 'Create',
  },
) {
  function WrappedComponent(props: any) {
    const { createComponent, title } = options;
    const [isOpen, setisOpen] = useState(false);

    function onCreateClick() {
      setisOpen(!isOpen);
      Util.prevDefault(() => setisOpen(isOpen));
    }

    return (
      <div>
        <ChildComponent {...props} />
        <div>
          <Component.Button
            key={'add'}
            big={true}
            round={true}
            primary={true}
            onClick={Util.prevDefault(onCreateClick)}
            className={'float-right'}
            tooltip={title}
          >
            <Component.Icon material={'add'} />
          </Component.Button>
        </div>
        <OpenDrawerWithClose
          open={isOpen}
          title={title}
          setisOpen={setisOpen}
          createComponent={createComponent}
        />
      </div>
    );
  }

  function mapStateToProps(state: any) {
    console.log('HOC mapStateToProps isOpen', state.isOpen);
    return {
      isOpen: state.isOpen,
    };
  }
  // Redux connected;
  return connect(mapStateToProps, {})(WrappedComponent);
}

期望從ReduxStore使用isOpen並在此處使用WrappedComponent進行更新。 這是否應該更改為 class 組件?

上述 HOC 用作:

export const Page = withCreateHOC(
  PageItems,
  {
    createComponent: <SomeOtherComponent />,
    title: 'Create',
  },
);

概述

您不希望isOpen成為 WrappedComponent 中的本地WrappedComponent 這個 HOC 的重點是從您的 redux 商店訪問isOpen 請注意,在此代碼中,您沒有更改 redux state 的值。 您想放棄本地 state,從 redux 訪問isOpen ,並dispatch一個操作以更改 redux 中的isOpen

此外,我們必須用實際類型替換其中的一些any

我似乎有點懷疑您傳遞的是已解析的 JSX 元素而不是可調用組件作為createComponent<SomeOtherComponent />SomeOtherComponent ),但這是正確還是錯誤取決於您的OpenDrawerWithClose組件中的內容。 我將假設它是正確的,如此處所寫。

使用connect在技術上沒有任何問題,但是在 HOC 內部使用 HOC 感覺有點奇怪,所以我將使用鈎子useSelectoruseDispatch代替。

一步步

我們想創建一個 function ,它接受一個組件ComponentType<ChildProps>和一些選項WithCreateButtonHOCOptions 您正在為options.title提供默認值,因此我們可以將其設為可選。 options.createComponent是可選的還是必需的?

interface WithCreateButtonHOCOptions {
    title: string;
    createComponent: React.ReactNode;
}
function withCreateHOC<ChildProps>(
  ChildComponent: ComponentType<ChildProps>,
  options: Partial<WithCreateButtonHOCOptions>
) {

我們返回一個 function ,它采用相同的道具,但沒有isOpentoggleOpen ,如果它們是ChildProps的屬性。

return function (props: Omit<ChildProps, 'isOpen' | 'toggleOpen'>) {

我們需要在解構步驟中為options設置默認值,以便只設置一個屬性。

const { createComponent, title = 'Create' } = options;

我們從 redux state 訪問isOpen

const isOpen = useSelector((state: { isOpen: boolean }) => state.isOpen);

我們創建了一個回調,它向 redux 發送一個動作——你需要在你的 reducer 中處理這個。 我正在調度一個原始動作 object {type: 'TOGGLE_OPEN'} ,但您可以為此創建一個動作創建者 function 。

const dispatch = useDispatch();
const toggleOpen = () => {
    dispatch({type: 'TOGGLE_OPEN'});
}

我們會將這兩個值isOpentoggleOpen作為 props 傳遞給ChildComponent ,以防萬一它想使用它們。 但更重要的是,我們可以將它們用作按鈕和抽屜組件的點擊處理程序。 (注意:看起來抽屜想要一個帶有boolean的道具setIsOpen ,所以你可能需要稍微調整一下。如果抽屜只在isOpentrue時顯示,那么只需切換就可以了)。

代碼

function withCreateHOC<ChildProps>(
    ChildComponent: ComponentType<ChildProps>,
    options: Partial<WithCreateButtonHOCOptions>
) {
    return function (props: Omit<ChildProps, 'isOpen' | 'toggleOpen'>) {
        const { createComponent, title = 'Create' } = options;

        const isOpen = useSelector((state: { isOpen: boolean }) => state.isOpen);

        const dispatch = useDispatch();
        const toggleOpen = () => {
            dispatch({ type: 'TOGGLE_OPEN' });
        }

        return (
            <div>
                <ChildComponent
                    {...props as ChildProps}
                    toggleOpen={toggleOpen}
                    isOpen={isOpen}
                />
                <div>
                    <Component.Button
                        key={'add'}
                        big={true}
                        round={true}
                        primary={true}
                        onClick={toggleOpen}
                        className={'float-right'}
                        tooltip={title}
                    >
                        <Component.Icon material={'add'} />
                    </Component.Button>
                </div>
                <OpenDrawerWithClose
                    open={isOpen}
                    title={title}
                    setisOpen={toggleOpen}
                    createComponent={createComponent}
                />
            </div>
        );
    }
}

這個版本稍微好一點,因為它沒有as ChildProps斷言。 我不想過於偏離“為什么”,但基本上我們需要堅持如果ChildProps采用isOpentoggleOpen道具,這些道具必須與我們提供的道具具有相同的類型。

interface AddedProps {
    isOpen: boolean;
    toggleOpen: () => void;
}

function withCreateHOC<ChildProps>(
    ChildComponent: ComponentType<Omit<ChildProps, keyof AddedProps> & AddedProps>,
    options: Partial<WithCreateButtonHOCOptions>
) {
    return function (props: Omit<ChildProps, keyof AddedProps>) {
        const { createComponent, title = 'Create' } = options;

        const isOpen = useSelector((state: { isOpen: boolean }) => state.isOpen);

        const dispatch = useDispatch();
        const toggleOpen = () => {
            dispatch({ type: 'TOGGLE_OPEN' });
        }

        return (
            <div>
                <ChildComponent
                    {...props}
                    toggleOpen={toggleOpen}
                    isOpen={isOpen}
                />
                <div>
                    <Component.Button
                        key={'add'}
                        big={true}
                        round={true}
                        primary={true}
                        onClick={toggleOpen}
                        className={'float-right'}
                        tooltip={title}
                    >
                        <Component.Icon material={'add'} />
                    </Component.Button>
                </div>
                <OpenDrawerWithClose
                    open={isOpen}
                    title={title}
                    setisOpen={toggleOpen}
                    createComponent={createComponent}
                />
            </div>
        );
    }
}

游樂場鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM