在 React 组件之间共享功能是一个非常普遍的需求。 这个概念是,我们可以在一个地方建立行为,然后将其扩展到不同的组件。 高阶组件 是实现此目的的一种方式。 但是,还有另一种方法可以使用一个名为 Recompose 的库。
什么是 Recompose?
该 文档 有助于我们回答这个问题
Recompose 是一个 React 实用工具带,用于函数组件和高阶组件。 可以将其视为 React 的 lodash。
基本上,它是一个 React 库,包含一堆助手,这些助手返回不同的高阶组件——这很好,因为它减少了定义常见 React 模式的繁琐工作,并使它们立即可用以扩展到其他组件。
它到底能做什么? 好吧,让我们一起浏览几个示例。
向函数无状态组件添加状态
顾名思义,函数无状态组件没有任何状态。 它只是接受 props 并将 UI 返回到前端。
const Greeting = props =>
<p>
Hello, {props.name}!
</p>
在您想在函数无状态组件中使用状态的场景中,您必须将其转换为类组件。 这正是 Recompose 发挥作用的地方。
Recompose 为您提供了 withState()
助手,以便向函数无状态组件添加状态。 它管理单个状态值。 您无法像在类组件中那样在 withState()
中管理多个状态值。 您传递一个函数来更新状态值,并传递一个可选的默认状态值。
以下是 withState()
的结构
withState(
stateName: string, // the name we call our state
stateUpdaterName: string, // the name of the function to call
initialState: any | (props: Object) => any // optional default state to pass
): HigherOrderComponent
计数器是一个常用的示例,用于演示概念。 以下是我们如何使用 Recompose 的 withState()
助手来创建一个超简单的计数器
const App = withState("count", "handleCounter", 0)(({ count, handleCounter }) => {
return (
<div>
<p>{count}</p>
<button onClick={() => handleCounter(n => n + 1)}>Increment</button>
<button onClick={() => handleCounter(n => n - 1)}>Decrement</button>
</div>
);
});
由于 withState()
助手已经对我们可用,我们可以立即调用它并为其提供所需的参数。 再次强调,它们是
stateName
:我们调用状态的名称stateUpdaterName
:要调用的函数的名称initialState
:要传递的可选默认状态
这些参数然后被集成到我们想要在前端渲染的 UI 标记中。
我们还可以通过另一种方式创建计数器组件,值得一看,以便更多地练习使用 Recompose 助手。
首先,我们使用 withState()
和所需的参数创建一个高阶组件。
const enhanced = withState("counter", "handleCounter", 0);
接下来,我们创建 Counter
组件,并在其中使用 withState()
参数
const Counter = ({ counter, handleCounter }) => (
<div>
<h1>{counter}</h1>
<button onClick={() => handleCounter(n => n + 1)}>Increment</button>
<button onClick={() => handleCounter(n => n - 1)}>Decrement</button>
</div>
);
请注意,状态和更新函数的名称作为 props 传递给 Counter
组件。
最后,我们通过将 Counter
组件包装在增强的高阶组件中来创建 App
组件。
const App = enhanced(Counter);
查看 CodePen 上 Kingsley Silas Chijioke (@kinsomicrote) 编写的 Recompose withState 。
这是另一种流行的方法
const enhanced = withState("count", "handleCounter", 0);
const App = enhanced(({ count, handleCounter }) => {
return (
<div>
<p>{count}</p>
<button onClick={() => handleCounter(n => n + 1)}>Increment</button>
<button onClick={() => handleCounter(n => n - 1)}>Decrement</button>
</div>
);
});
查看 CodePen 上 Kingsley Silas Chijioke (@kinsomicrote) 编写的 Recompose withState v2。
使用 withHandlers() 处理状态
Recompose 还具有 withHandlers()
助手,它允许您通过定义用于更新组件状态的函数来处理状态。 而且,您可以将其与 withState()
一起使用!
这些基本上是高阶函数,它们接收 props 并返回函数处理程序。 让我们像在前面的示例中一样分解结构。
withHandlers({
incrementCounter: props => event => {
event.preventDefault();
props.handleCounter(props.count + 1);
}
})
首先,我们确定了 incrementCounter
,它将对我们的 Counter
组件可用,以便在单击时更新计数值。
接下来,我们像以前一样构造计数器——作为使用 withState()
的高阶组件
const enhancedState = withState("count", "handleCounter", 0);
现在,我们定义我们的函数并使用 withHandlers()
const enhancedHandler = withHandlers({
incrementCounter: props => event => {
event.preventDefault();
props.handleCounter(props.count + 1);
},
decrementCounter: props => event => {
event.preventDefault();
props.handleCounter(props.count - 1);
}
});
我们构造了一个我们称之为 enhancedHandler
的高阶组件,并在其中使用 withState()
定义了两个函数处理程序:incrementCounter
和 decrementCounter
。 这些处理程序包含将作为 props 由调用它们的组件接收的参数。 如果我们想更新使用 withState()
定义的组件的状态,则需要它们。
好的,现在开始创建我们的计数器组件
const Counter = ({ count, incrementCounter, decrementCounter }) => (
<div>
<h1>{count}</h1>
<button onClick={incrementCounter}>Increment</button>
<button onClick={decrementCounter}>Decrement</button>
</div>
);
看到了吗? 预计将状态和处理程序作为 props 传递给计数器组件。
要使用我们定义的高阶组件,我们必须将 Counter
组件传递给 enhancedHandler
,并将该组件作为参数包装到 enhancedState
中。
换句话说
const App = enhancedState(enhancedHandler(Counter));
查看 CodePen 上 Kingsley Silas Chijioke (@kinsomicrote) 编写的 Recompose withState & withHandlers。
组合多个高阶组件
在最后一个示例中,我们使用了两个高阶组件。 有没有更好的方法将它们链接在一起? 绝对有! Recompose 为我们提供了 compose()
助手来实现这一点。 我们可以使用 compose()
创建一个组件,该组件将两个高阶组件在一个步骤中组合在一起。
const enhanced = compose(
withState("count", "handleCounter", 0),
withHandlers({
incrementCounter: props => event => {
event.preventDefault();
props.handleCounter(props.count + 1);
},
decrementCounter: props => event => {
event.preventDefault();
props.handleCounter(props.count - 1);
}
})
);
现在,我们可以在 App
组件中使用增强组件
const App = enhanced(({ count, incrementCounter, decrementCounter }) => {
return (
<div>
<p>{count}</p>
<button onClick={incrementCounter}>Increment</button>
<button onClick={decrementCounter}>Decrement</button>
</div>
);
});
查看 CodePen 上 Kingsley Silas Chijioke (@kinsomicrote) 编写的 Recompose – compose withState & withHandlers。
使用类似 Redux 的 reducer 管理状态
Recompose 的另一个优点是允许您使用 reducer 函数 (withReducer
) 来管理状态。 reducer 会响应特定操作来更新组件的状态。
withReducer()
的结构如下所示
withReducer<S, A>(
stateName: string,
dispatchName: string,
reducer: (state: S, action: A) => S,
initialState: S | (ownerProps: Object) => S
): HigherOrderComponent</S>
第一个参数是状态的名称。 第二个是 dispatch
方法。 dispatch
将用于分派操作,就像我们在 Redux 中所做的那样。 接下来,我们有 reducer
和初始状态。
在计数器组件的上下文中,withReducer()
将更新计数的状态:计数将随着我们称之为“增加”的操作而增加,反之,计数将随着我们称之为“减少”的操作而减少。
首先,我们通过组合 withReducer
和 withHandlers
来创建一个增强组件。
const enhanced = compose(
withReducer(
"count",
"dispatch",
(state, action) => {
switch (action.type) {
case "INCREMENT":
return state + 1;
case "DECREMENT":
return state - 1;
default:
return state;
}
},
0
),
withHandlers({
incrementCounter: ({ dispatch }) => e => dispatch({ type: "INCREMENT" }),
decrementCounter: ({ dispatch }) => e => dispatch({ type: "DECREMENT" })
})
);
incrementCounter
和 decrementCounter
将响应 DOM 事件并分派操作类型。 状态将根据操作类型进行更新。 接下来,我们需要在组件中使用它。
const App = enhanced(({ count, incrementCounter, decrementCounter }) => {
return (
<div>
<p>{count}</p>
<button onClick={incrementCounter}>Increment</button>
<button onClick={decrementCounter}>Decrement</button>
</div>
);
});
查看 CodePen 上 Kingsley Silas Chijioke (@kinsomicrote) 编写的 Recompose – reducer。
非常棒,对吧?
希望这能让你对 Recompose 是什么以及库中的丰富助手如何简化 React 开发有一个很好的了解,特别是在管理和调用状态方面。
当然,Recompose 比我们这里介绍的内容要多得多。 快速浏览一下 API 文档 将显示,您根据应用程序的要求可以使用许多高阶组件。 开始构建吧,如果您有任何问题,请随时在下方留言!