ReactJS 中的高阶组件 - 从数据组件扩展功能
Higher-Order Components in ReactJS - extend functionalities from data components
很抱歉问了这个愚蠢的问题,我正在学习 React,所以我根本不是专家。
我想知道是否有一种方法可以使用某些功能扩展我的无状态组件,而无需始终围绕它们创建包装器,它们将连接到 Redux 存储并通过 props 传递数据。
高阶组件是最好的方法吗?
让我用几行代码更好地解释一下。
下面的示例组件应该在用户单击事件上调用 API /favourites (POST) 以创建 "Favourite" 实体,并且它将调用相同的 API (DELETE ) 以便将其删除。
这是我实现的解决方案:
const HOC_DISPLAY_NAME = 'HOCFavouriteIcon';
export default function HOCWrapperFavourite(FavouriteComponent) {
return class extends React.Component {
static displayName = HOC_DISPLAY_NAME;
constructor(props) {
super(props);
this.state = this.getDefaultState();
this.bindMethods();
}
getDefaultState() {
return {
isFavourite: false,
addFavouritePayload: null,
removeFavouritePayload: null,
};
}
render() {
return (
<DataProviderApiFavourites
create={this.state.addFavouritePayload}
createListener={this.favoriteCreateHandler}
delete={this.state.removeFavouritePayload}
deleteListener={this.favoriteDeleteHandler}
>
<FavouriteComponent
{...this.props}
{...this.state}
addFavourite={this.addFavouriteClickHandler}
removeFavourite={this.removeFavouriteClickHandler}
/>
</DataProviderApiFavourites>
);
}
addFavouriteClickHandler(visitorId, artId) {
this.setState({
addFavouritePayload: {visitorId, artId},
});
}
removeFavouriteClickHandler(visitorId, favouriteId) {
this.setState({
removeFavouritePayload: {visitorId, favouriteId},
});
}
favoriteCreateHandler(result){
// do something when a favorite entity was created
}
favoriteDeleteHandler(result){
// do something when a favorite entity was deleted
}
bindMethods() {
this.addFavouriteClickHandler = this.addFavouriteClickHandler.bind(this);
this.removeFavouriteClickHandler = this.removeFavouriteClickHandler.bind(this);
this.favoriteCreateHandler = this.favoriteCreateHandler.bind(this);
this.favoriteDeleteHandler = this.favoriteDeleteHandler.bind(this);
}
}
};
DataProviderApiFavourites 有一个 属性 "create" 接受一个 JSON 负载,它会触发一个被 Saga 捕获的 Redux 动作(谁会调用 API )和它还能够通过 createListener 函数通知结果。
它对 delete prop 做同样的事情(但它会调用 delete API 并通过 favoriteDeleteHandler 通知)。
考虑到 FavouriteComponent 是一个无状态组件,为了在 UI 个组件中使用来自数据组件的功能,它是一个好的结构吗?
实际上,可以在不嵌套子组件的情况下使用 DataProviderApiFavourites,它 returns null 或 this.props.children if 已设置。
如果有人能帮助我理解我是否会做错事,我将不胜感激。
当然,HOC 非常适合这个用例。
代码很好,但是,为了坚持组合和可重用性的想法,我会构建一个更通用的 HOC,不要在其中放入那么多逻辑,然后如果您需要更具体的东西,传递参数或在其上构建另一个 HOC。
例如:
const HOC = store => WrappedComponent => props => (
// Render your wrapped component, spread the store to his props
);
将存储作为参数传递给 HOC 的位置,然后如果需要它的特定片段,请将其指定为第一个参数或使用另一个 HOC 抽象。
简而言之,与其使用直接接受包装组件的 HOC,不如创建另一个接受第一个参数的 HOC,这将为您提供更大的灵活性。第一个参数可以是 redux 存储、解构的 redux 存储、默认状态等,具体取决于您选择使用的逻辑。
- 或者,recompose 也可以满足您的需求。
- 同样,或者,你可以为 redux 的连接做一个 HOC,看看
很抱歉问了这个愚蠢的问题,我正在学习 React,所以我根本不是专家。
我想知道是否有一种方法可以使用某些功能扩展我的无状态组件,而无需始终围绕它们创建包装器,它们将连接到 Redux 存储并通过 props 传递数据。
高阶组件是最好的方法吗?
让我用几行代码更好地解释一下。 下面的示例组件应该在用户单击事件上调用 API /favourites (POST) 以创建 "Favourite" 实体,并且它将调用相同的 API (DELETE ) 以便将其删除。
这是我实现的解决方案:
const HOC_DISPLAY_NAME = 'HOCFavouriteIcon';
export default function HOCWrapperFavourite(FavouriteComponent) {
return class extends React.Component {
static displayName = HOC_DISPLAY_NAME;
constructor(props) {
super(props);
this.state = this.getDefaultState();
this.bindMethods();
}
getDefaultState() {
return {
isFavourite: false,
addFavouritePayload: null,
removeFavouritePayload: null,
};
}
render() {
return (
<DataProviderApiFavourites
create={this.state.addFavouritePayload}
createListener={this.favoriteCreateHandler}
delete={this.state.removeFavouritePayload}
deleteListener={this.favoriteDeleteHandler}
>
<FavouriteComponent
{...this.props}
{...this.state}
addFavourite={this.addFavouriteClickHandler}
removeFavourite={this.removeFavouriteClickHandler}
/>
</DataProviderApiFavourites>
);
}
addFavouriteClickHandler(visitorId, artId) {
this.setState({
addFavouritePayload: {visitorId, artId},
});
}
removeFavouriteClickHandler(visitorId, favouriteId) {
this.setState({
removeFavouritePayload: {visitorId, favouriteId},
});
}
favoriteCreateHandler(result){
// do something when a favorite entity was created
}
favoriteDeleteHandler(result){
// do something when a favorite entity was deleted
}
bindMethods() {
this.addFavouriteClickHandler = this.addFavouriteClickHandler.bind(this);
this.removeFavouriteClickHandler = this.removeFavouriteClickHandler.bind(this);
this.favoriteCreateHandler = this.favoriteCreateHandler.bind(this);
this.favoriteDeleteHandler = this.favoriteDeleteHandler.bind(this);
}
}
};
DataProviderApiFavourites 有一个 属性 "create" 接受一个 JSON 负载,它会触发一个被 Saga 捕获的 Redux 动作(谁会调用 API )和它还能够通过 createListener 函数通知结果。 它对 delete prop 做同样的事情(但它会调用 delete API 并通过 favoriteDeleteHandler 通知)。
考虑到 FavouriteComponent 是一个无状态组件,为了在 UI 个组件中使用来自数据组件的功能,它是一个好的结构吗?
实际上,可以在不嵌套子组件的情况下使用 DataProviderApiFavourites,它 returns null 或 this.props.children if 已设置。
如果有人能帮助我理解我是否会做错事,我将不胜感激。
当然,HOC 非常适合这个用例。
代码很好,但是,为了坚持组合和可重用性的想法,我会构建一个更通用的 HOC,不要在其中放入那么多逻辑,然后如果您需要更具体的东西,传递参数或在其上构建另一个 HOC。
例如:
const HOC = store => WrappedComponent => props => (
// Render your wrapped component, spread the store to his props
);
将存储作为参数传递给 HOC 的位置,然后如果需要它的特定片段,请将其指定为第一个参数或使用另一个 HOC 抽象。
简而言之,与其使用直接接受包装组件的 HOC,不如创建另一个接受第一个参数的 HOC,这将为您提供更大的灵活性。第一个参数可以是 redux 存储、解构的 redux 存储、默认状态等,具体取决于您选择使用的逻辑。
- 或者,recompose 也可以满足您的需求。
- 同样,或者,你可以为 redux 的连接做一个 HOC,看看