[英]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 感覺有點奇怪,所以我將使用鈎子useSelector
和useDispatch
代替。
我們想創建一個 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 ,它采用相同的道具,但沒有isOpen
或toggleOpen
,如果它們是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'});
}
我們會將這兩個值isOpen
和toggleOpen
作為 props 傳遞給ChildComponent
,以防萬一它想使用它們。 但更重要的是,我們可以將它們用作按鈕和抽屜組件的點擊處理程序。 (注意:看起來抽屜想要一個帶有boolean
的道具setIsOpen
,所以你可能需要稍微調整一下。如果抽屜只在isOpen
為true
時顯示,那么只需切換就可以了)。
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
采用isOpen
或toggleOpen
道具,這些道具必須與我們提供的道具具有相同的類型。
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.