一行代码实现 React Hooks 与 JSX 的混写:comp-in-one
大家好,今天是 4 月 1 日愚人节,我想向大家介绍一个我开发的 NPM 包comp-in-one
。它通过某种“黑魔法”,可以达到在 JSX 中写 React Hooks 的效果,无需额外创建组件。下面我们就一起来看看它是如何使用的吧。
基础用法
首先通过 npm 安装 comp-in-one
:
npm install comp-in-one
然后在代码中引入 Comp
组件:
import { Comp } from 'comp-in-one';
现在我们可以直接在 JSX 中使用它了:
<Comp>
{() => <div>Hello World</div>}
</Comp>
没错,就是这么简单!Comp
组件接受一个返回 JSX 的函数作为 children。在函数内部,我们可以像平常一样写 JSX。
与 React Hooks 混写
你可能会问:上面的例子有什么特别的?为什么要无缘无故多加一层函数?实际上,comp-in-one
的一大亮点体现在可以让我们直接在 JSX 中使用 React Hooks。比如:
<Comp>
{() => {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}}
</Comp>
在 Comp
的 children 函数中,我们可以像在组件里那样使用 useState
、useEffect
等各种 Hooks,非常方便。
嵌套使用
Comp
组件是可以嵌套使用的。比如:
<Comp>
{() => {
const [count, setCount] = useState(0);
return (
<div>
<Comp>
{() => {
useEffect(() => {
console.log('inner comp mounted');
}, []);
return <p>You clicked {count} times</p>;
}}
</Comp>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}}
</Comp>
在外层 Comp
中定义的状态和函数,在内层的 Comp
中也可以访问到,无需 prop drilling。
条件渲染
通过设置不同的 key
,comp-in-one
支持条件渲染。比如:
<>
{isTrue && (
<Comp key="a">
{() => {
const [count, setCount] = useState(0);
return <div>{count}</div>;
}}
</Comp>
)}
{!isTrue && (
<Comp key="b">
{() => {
useEffect(() => {
console.log('mounted');
}, []);
return <div>Content</div>;
}}
</Comp>
)}
</>
在条件渲染的场景下,设置了不同key的 Comp
组件内部使用的 Hooks 数量可以不一致。这并不会触发 React 开发模式的警告。
优化重渲染
尽管 Comp
组件在 JSX 中的使用非常方便,但有的时候我们还是希望对其进行优化,避免不必要的重渲染。这时可以利用 useMemo
对 Comp
组件进行包装:
const MyComp = () => {
const [count, setCount] = useState(0);
return;
<div>
<p>{count}</p>
<button onClick={() => setCount((c) => c + 1)}>+</button>
<Comp>
{() =>
useMemo(
() => (
<Comp>
{() => {
return <div>foo</div>;
}}
</Comp>
),
[],
)
}
</Comp>
</div>;
};
在上面的代码中,我们用 useMemo
包装了 Comp
组件,传入一个空数组作为依赖数组,并在外部再包装一层 Comp
来保证 Hooks 的正确使用。这样当父组件的 count
状态发生变化时,内部的 Comp
不会被重新执行,从而避免了重渲染。
这种优化方式在 Comp
组件内部渲染开销比较大时尤为有用。合理使用 useMemo
,可以让我们在享受 comp-in-one
带来的灵活性的同时,也能保证应用的性能。
原理揭秘
文章看到这里,相信大家已经学会了 comp-in-one
的使用,也体会到了它可能带来的便利。那么它的内部是如何实现的呢?
其实 comp-in-one
的源码非常简洁,整个包的核心仅仅是一行代码:
export function Comp({ children }) {
return children();
}
没错,Comp
组件就是简简单单地执行传入的 children 函数并返回结果而已。之所以能够处理 Hooks,是因为 React 看到的是 Comp
这一个组件,期望它返回一个 ReactElement,React 并不关心内部的过程。而我们利用这个机会,在内部执行传入的 children 函数,让其中的 Hooks 调用成为在组件顶层的合法调用。事实上,在这个过程中,我们很好地遵循了 React Hooks 的规则。
总结
comp-in-one
通过一个接口简洁的 Comp
组件,利用 React 本身的机制,极大简化了组织 Hooks 与 JSX 代码的方式。当然,它绝不是“银弹”,在实际的大型项目中,我们应该合理地拆分组件,组织代码结构。但 comp-in-one
给了我们一个全新的思路,让我们看到 React 开发可以更灵活、更高效。
希望今天的分享对大家有所启发。如果你想深入了解 comp-in-one
,欢迎访问 GitHub 仓库:github.com/CoolSpring8…
Happy coding!
转载自:https://juejin.cn/post/7352727612659073062