除了基本组件的其余属性之外,如何指定高阶组件应该接受 属性?
How do I specify that a Higher Order Component should accept a property in addition to the remaining properties of the base component?
我正在尝试学习 React / Redux 在 Typescript 环境中使用高阶组件。我有两个高阶组件:
- withId:为基本组件
生成uniqueId 属性
- withErrorListener:在 redux 存储上呈现错误,源自基本组件请求。基本组件应具有从 withId 高阶组件创建的 uniqueId 属性。
NewComponent = withErrorListener(withId(BaseComponent))
const PostsListWithId = withId(PostsListBase);
export const PostsListConnected = connector(withErrorListener(PostsListWithId));
我正在按如下方式使用 HoC:
import * as React from "react";
import { connect, ConnectedProps } from "react-redux";
import { Link } from "react-router-dom";
import { RootState } from "typesafe-actions";
import { Post as PostComponent } from "../components/Post";
import { allPostsAction, createPostsRequest } from "../features/posts/actions";
import { HocComponentProps } from "../higher-order-components/types";
import { Post } from "../features/posts/types";
import { withErrorListener } from "../higher-order-components/withErrorListener";
import { withId } from "../higher-order-components/componentId/withId";
type StateProps = {
isLoading: boolean;
posts: Post[];
};
/**
* Redux dispatch and state mappings
*/
const dispatchProps = {
fetchPosts: allPostsAction.request
};
const mapStateToProps = (state: RootState): StateProps => ({
isLoading: state.posts.isLoadingPosts,
posts: state.posts.posts
});
const connector = connect(
mapStateToProps,
dispatchProps
);
type ReduxProps = ConnectedProps<typeof connector>;
/**
* Component property type definitions
*/
type Props = ReduxProps & HocComponentProps;
/**
* CourseList component
*/
const PostsListBase = ({
posts = [],
uniqueId,
fetchPosts,
isLoading
}: Props): JSX.Element => {
console.log(`PostListBase id :: ${uniqueId}`);
// dispatch fetch posts action on mount
React.useEffect(() => {
console.log(
`PostListBase dispatching PostsRequest action with id ${uniqueId}`
);
fetchPosts(createPostsRequest(uniqueId));
}, [fetchPosts, uniqueId]);
if (isLoading) {
return (
<>
<p>Loading...</p>
<Link to="/">Home</Link>
</>
);
}
return (
<div style={{ marginTop: 20, padding: 30 }}>
<Link to="/">Home</Link>
<h2>List of post id's</h2>
{
<ul>
{posts.map(element => (
<li key={element.id}>
<PostComponent post={element} />
</li>
))}
</ul>
}
</div>
);
};
const PostsListWithId = withId(PostsListBase);
export const PostsListConnected = connector(withErrorListener(PostsListWithId));
/**
* Argument of type 'typeof IdHoC' is not assignable to parameter of type 'ComponentType<ExpectedProps>'.
Type 'typeof IdHoC' is not assignable to type 'ComponentClass<ExpectedProps, any>'.
Types of parameters 'hocprops' and 'props' are incompatible.
Type 'ExpectedProps' is missing the following properties from type 'Pick<Props, "posts" | "fetchPosts" | "isLoading">': posts, fetchPosts, isLoadingts(2345)
*/
但是,我收到以下打字稿编译错误:
Argument of type 'typeof IdHoC' is not assignable to parameter of type 'ComponentType<ExpectedProps>'.
Type 'typeof IdHoC' is not assignable to type 'ComponentClass<ExpectedProps, any>'.
Types of parameters 'hocprops' and 'props' are incompatible.
Type 'ExpectedProps' is missing the following properties from type 'Pick<Props, "posts" | "fetchPosts" | "isLoading">': posts, fetchPosts, isLoadingts(2345)
如何正确指定 withErrorListener 高阶组件应接受包含 uniqueId 属性 的类型除了基本组件中的其余属性,在本例中为:{posts、fetchPosts 和 isLoading}?
我目前正尝试在代码中执行此操作,如下所示:
type ExpectedProps = { uniqueId: string };
export const withErrorListener = <BaseProps extends ExpectedProps>(
BaseComponent: React.ComponentType<BaseProps>
) => {....}
我已经创建了一个 codesandbox 项目,包括高阶组件的源代码,在这里:
认为我已经设法解决了这个问题。下面的评论中提出了一个问题,关于 withId 返回一个包装组件,不包括注入的 id 属性。已删除此约束并接受该评论作为解决方案。另一个问题是消费组件需要连接到 redux 存储的属性来接收从 Api 获取的状态。将高级组件的消费者更新为:
// ensure consuming component is connected to redux store to fulfill it's other property requirements
const PostsListConnectedWithId = connector(withId(PostsListBase));
export const PostsListWithErrorListener = withErrorListener(PostsListConnectedWithId);
打字稿
相对于:
const PostsListWithId = withId(PostsListBase);
export const PostsListWithErrorListener = connector(withErrorListener(PostsListWithId));
我查看了您的 CodeSandbox 示例,我不太了解您的需求。
所以在你的代码中,withId
HoC 采用一个基础组件,在你的情况下 PostsListBase
,并向它注入 uniqueId
prop,然后 return 一个包装组件 不再需要 uniqueId
作为 prop 输入,因为它已经从 withId
.
获得了它
然后你把不再想要 uniqueId
的 WrappedPostsListBase
通过 withErrorListener(WrappedPostsListBase)
.
这是令人困惑的部分,您指定 withErrorListener
仅接受 需要 一个 uniqueId
道具的基础合成输入。看到冲突了吗?
我正在尝试学习 React / Redux 在 Typescript 环境中使用高阶组件。我有两个高阶组件:
- withId:为基本组件 生成uniqueId 属性
- withErrorListener:在 redux 存储上呈现错误,源自基本组件请求。基本组件应具有从 withId 高阶组件创建的 uniqueId 属性。
NewComponent = withErrorListener(withId(BaseComponent))
const PostsListWithId = withId(PostsListBase);
export const PostsListConnected = connector(withErrorListener(PostsListWithId));
我正在按如下方式使用 HoC:
import * as React from "react";
import { connect, ConnectedProps } from "react-redux";
import { Link } from "react-router-dom";
import { RootState } from "typesafe-actions";
import { Post as PostComponent } from "../components/Post";
import { allPostsAction, createPostsRequest } from "../features/posts/actions";
import { HocComponentProps } from "../higher-order-components/types";
import { Post } from "../features/posts/types";
import { withErrorListener } from "../higher-order-components/withErrorListener";
import { withId } from "../higher-order-components/componentId/withId";
type StateProps = {
isLoading: boolean;
posts: Post[];
};
/**
* Redux dispatch and state mappings
*/
const dispatchProps = {
fetchPosts: allPostsAction.request
};
const mapStateToProps = (state: RootState): StateProps => ({
isLoading: state.posts.isLoadingPosts,
posts: state.posts.posts
});
const connector = connect(
mapStateToProps,
dispatchProps
);
type ReduxProps = ConnectedProps<typeof connector>;
/**
* Component property type definitions
*/
type Props = ReduxProps & HocComponentProps;
/**
* CourseList component
*/
const PostsListBase = ({
posts = [],
uniqueId,
fetchPosts,
isLoading
}: Props): JSX.Element => {
console.log(`PostListBase id :: ${uniqueId}`);
// dispatch fetch posts action on mount
React.useEffect(() => {
console.log(
`PostListBase dispatching PostsRequest action with id ${uniqueId}`
);
fetchPosts(createPostsRequest(uniqueId));
}, [fetchPosts, uniqueId]);
if (isLoading) {
return (
<>
<p>Loading...</p>
<Link to="/">Home</Link>
</>
);
}
return (
<div style={{ marginTop: 20, padding: 30 }}>
<Link to="/">Home</Link>
<h2>List of post id's</h2>
{
<ul>
{posts.map(element => (
<li key={element.id}>
<PostComponent post={element} />
</li>
))}
</ul>
}
</div>
);
};
const PostsListWithId = withId(PostsListBase);
export const PostsListConnected = connector(withErrorListener(PostsListWithId));
/**
* Argument of type 'typeof IdHoC' is not assignable to parameter of type 'ComponentType<ExpectedProps>'.
Type 'typeof IdHoC' is not assignable to type 'ComponentClass<ExpectedProps, any>'.
Types of parameters 'hocprops' and 'props' are incompatible.
Type 'ExpectedProps' is missing the following properties from type 'Pick<Props, "posts" | "fetchPosts" | "isLoading">': posts, fetchPosts, isLoadingts(2345)
*/
但是,我收到以下打字稿编译错误:
Argument of type 'typeof IdHoC' is not assignable to parameter of type 'ComponentType<ExpectedProps>'.
Type 'typeof IdHoC' is not assignable to type 'ComponentClass<ExpectedProps, any>'.
Types of parameters 'hocprops' and 'props' are incompatible.
Type 'ExpectedProps' is missing the following properties from type 'Pick<Props, "posts" | "fetchPosts" | "isLoading">': posts, fetchPosts, isLoadingts(2345)
如何正确指定 withErrorListener 高阶组件应接受包含 uniqueId 属性 的类型除了基本组件中的其余属性,在本例中为:{posts、fetchPosts 和 isLoading}?
我目前正尝试在代码中执行此操作,如下所示:
type ExpectedProps = { uniqueId: string };
export const withErrorListener = <BaseProps extends ExpectedProps>(
BaseComponent: React.ComponentType<BaseProps>
) => {....}
我已经创建了一个 codesandbox 项目,包括高阶组件的源代码,在这里:
认为我已经设法解决了这个问题。下面的评论中提出了一个问题,关于 withId 返回一个包装组件,不包括注入的 id 属性。已删除此约束并接受该评论作为解决方案。另一个问题是消费组件需要连接到 redux 存储的属性来接收从 Api 获取的状态。将高级组件的消费者更新为:
// ensure consuming component is connected to redux store to fulfill it's other property requirements
const PostsListConnectedWithId = connector(withId(PostsListBase));
export const PostsListWithErrorListener = withErrorListener(PostsListConnectedWithId);
打字稿
相对于:
const PostsListWithId = withId(PostsListBase);
export const PostsListWithErrorListener = connector(withErrorListener(PostsListWithId));
我查看了您的 CodeSandbox 示例,我不太了解您的需求。
所以在你的代码中,withId
HoC 采用一个基础组件,在你的情况下 PostsListBase
,并向它注入 uniqueId
prop,然后 return 一个包装组件 不再需要 uniqueId
作为 prop 输入,因为它已经从 withId
.
然后你把不再想要 uniqueId
的 WrappedPostsListBase
通过 withErrorListener(WrappedPostsListBase)
.
这是令人困惑的部分,您指定 withErrorListener
仅接受 需要 一个 uniqueId
道具的基础合成输入。看到冲突了吗?