render props模式
render props 是一种在React组件之间传递一个名为 render 的函数的模式,这个函数返回一个React元素。render props 模式允许组件通过其props接收一个函数,该函数负责决定组件如何渲染。这种方法提供了一种高度灵活的方式来构建可重用的组件。
示例:
假设我们有一个 Button 组件,我们想要根据不同的条件渲染不同的按钮样式或行为:
// ButtonWithRenderProp.js
import React from 'react';
const ButtonWithRenderProp = ({ render }) => {
const onClick = () => {
console.log('Button clicked!');
};
return (
<div>
{render({ onClick })}
</div>
);
};
export default ButtonWithRenderProp;
现在,我们可以这样使用这个组件:
// App.js
import React from 'react';
import ButtonWithRenderProp from './ButtonWithRenderProp';
const App = () => {
return (
<ButtonWithRenderProp
render={({ onClick }) => (
<button onClick={onClick} style={{ background: 'blue', color: 'white' }}>
Click me!
</button>
)}
/>
);
};
export default App;
在这个例子中,ButtonWithRenderProp 组件接收一个 render 函数作为prop,这个函数接收一个对象,其中包含一个 onClick 函数。然后,render 函数返回一个按钮元素,它使用传递进来的 onClick 函数。
render props 的特点:
- 动态渲染:组件可以动态决定如何渲染,基于传递给它的
render函数。 - 解耦组件:
render props允许你将组件的行为(通过render函数)与其结构(组件本身的JSX)解耦。 - 可组合性:使用
render props,你可以轻松地组合多个组件,每个组件都可以贡献一部分渲染逻辑。
使用场景:
- 动态组件:当你需要基于某些条件渲染不同的组件时。
- 抽象UI:当你想要创建一个组件,它可以适应多种不同的渲染需求时。
- 传递行为:当你想要将渲染逻辑作为props传递给子组件时。
render props模式最重要的是它返回一个react元素,比如我将上面的render属性改名,依然有效。
import React from 'react';
const SharedComponentWithGoofyName extends React.Component {
render() {
return (
<div>
{this.props.wrapThisThingInADiv()}
</div>
);
}
}
const SayHelloWithGoofyName = () => (
<SharedComponentWithGoofyName wrapThisThingInADiv={() => (
<span>hello!</span>
)} />
);
HOC设计模式
高阶组件(Higher Order Component,HOC)是React中用于重用组件逻辑的一种高级技术。它本身不是一个React组件,而是一个函数,这个函数接受一个组件作为参数,并返回一个新的组件。HOC让你能够重用组件之间的代码,如事件处理、订阅数据源、注入主题等,而不必在每个组件中重复这些代码。
高阶组件在React生态链技术中经常用到,对读者较为熟悉的,比如Redux中的connect,React Router中的withRouter等。
HOC的主要特点:
- 参数传递:HOC接收一个组件作为参数。
- 返回组件:HOC返回一个新的组件。
- 可重用性:通过HOC,你可以创建可重用的组件逻辑。
- 无侵入性:HOC不会修改传入的组件,也不会使用继承,因此它们可以更容易地进行测试,并且可以保持干净。
使用场景:
- 代码复用:当多个组件需要相同的功能时,可以使用HOC来避免重复代码。
- 动态props注入:HOC可以添加新的props到组件,或者修改传递给子组件的props。
- 渲染劫持:HOC可以在渲染组件之前或之后执行操作。
- 关注点分离:将组件的业务逻辑和UI分离,使得组件更加专注于UI的展示。
代码示例
import React from 'react';
// 假设的认证服务,用于模拟检查登录状态
const AuthService = {
isAuthenticated: () => {
// 这里可以是异步操作,比如从localStorage获取token,然后验证token的有效性
// 模拟检查localStorage中是否有token
const token = localStorage.getItem('userToken');
return !!token; // 如果有token,返回true,表示用户已登录
}
};
function withAuth(WrappedComponent) {
return class extends React.Component {
render() {
const isLoggedIn = AuthService.isAuthenticated();
return <WrappedComponent isLoggedIn={isLoggedIn} {...this.props} />;
}
};
}
// 示例组件,使用HOC注入的isLoggedIn prop
class SomeComponent extends React.Component {
render() {
const { isLoggedIn } = this.props;
if (isLoggedIn) {
return <div>Welcome, you are logged in!</div>;
} else {
return <div>Please log in to continue.</div>;
}
}
}
const AuthenticatedComponent = withAuth(SomeComponent);
export default AuthenticatedComponent;
相同点:
- 组件复用:HOC和Render Props都是用于实现组件复用的技术,使得我们可以在多个组件之间共享功能。
- 非侵入性:它们都是以非侵入性的方式添加功能到现有组件,不需要修改原始组件的代码。
不同点:
- 抽象层级:HOC是一种在React中复用组件逻辑的高级技术。它实际上是一个函数,接受一个组件作为参数,并返回一个新的组件。这种方式可以使得组件逻辑与原始组件解耦,但可能会产生嵌套层级。 Render Props是通过props将一个函数传递给组件,这个函数允许组件在渲染时获取到特定的数据或行为。这样可以更加灵活地控制组件的行为。
- 组件结构:使用HOC时,我们在组件之外创建一个包裹组件,它会对原始组件进行包装,从而添加额外的功能。这意味着我们需要编写一个高阶函数来创建新的组件。 使用Render Props时,我们在组件内部定义一个特定的prop,它是一个函数,用于传递所需的功能或数据。这种方式更加直接,不需要额外的高阶函数。
- 数据流:HOC可以通过props将数据传递给被包装的组件,但它不能直接访问被包装组件的state。在HOC中,数据流是从外部向内部。 Render Props允许组件在渲染过程中向内部传递数据,通常是通过props中的回调函数。在Render Props中,数据流是从内部向外部。