- Published on
2023-1-1-前端快报
- Authors
- Name
- noodles
- 每个人的花期不同,不必在乎别人比你提前拥有
New Suspense SSR Architecture in React 18
这篇文章介绍react 18中流式渲染和Suspense的结合,实现更好的服务端渲染功能。相关文章还有浅析React 18 Streaming SSR
React Libraries for 2022
这篇文章介绍2022年热度比较高的React库
一文详解 CSS-in-JS
这篇文章从CSS规范、CSS的设计模式说起,逐步覆盖到CSS-in-JS的细节,涉及的相关背景比较多,值得仔细阅读。
What is a realm in JavaScript?
这篇文章介绍JavaScript中Realm的定义。也可以结合这篇ShadowRealms – an ECMAScript proposal for a better eval()介绍ShadowRealms API提议的文章一起了解。
Developer Roadmaps
Developer Roadmaps收集了各个开发方向的技能路线图
How we configured pnpm and Turborepo for our monorepo
一篇比较详细的介绍monorepo技术方案选择工具的文章,从多项目开发的问题开始说起,逐步介绍pnpm(monorepo管理工具)和Turborepo(打包构建工具)
工具
js-code-to-svg-flowchart
一个将JavaScript代码转化成svg图片的库。
CONSOLE NINJA
一款VSCode插件,可以直接在代码中查看输入的console调试信息
源码解读
react-wrap-balancer
react-wrap-balancer能使文案比较智能的适应容器,占据容器的空间,达到比较好的展示效果,下面从源码上看它是如何实现的:
通过简单的demo使用可以发现balancer在页面中注入了一段脚本并且为包裹的文本内容绑定的属性标识 


// react-wrap-balancer的主体代码逻辑
const Balancer: React.FC<BalancerProps> = ({
as: Wrapper = 'span',
ratio = 1,
children,
...props
}) => {
// 利用useId为组件生成唯一标识,useId可以根据组件的层级结构生成唯一标识
const id = React.useId()
const wrapperRef = React.useRef<WrapperElement>()
const hasProvider = React.useContext(BalancerContext)
// 监听函数执行
// useIsomorphicLayoutEffect这里对服务端和客户端做了区分 在服务端调用useEffect,在客户端调用useLayoutEffect 解决客户端的闪动问题
useIsomorphicLayoutEffect(() => {
if (wrapperRef.current) {
// 调用绑定self上绑定的动态调整函数 并传入当前的入参执行
// self可以指代全局的window https://developer.mozilla.org/en-US/docs/Web/API/Window/self
// 主要计算逻辑都在relayout函数中
;(self[SYMBOL_KEY] = relayout)(0, ratio, wrapperRef.current)
}
}, [children, ratio])
// 自己卸载的时候 终止监听函数
useIsomorphicLayoutEffect(() => {
return () => {
if (!wrapperRef.current) return
const resizeObserver = wrapperRef.current[SYMBOL_OBSERVER_KEY]
if (!resizeObserver) return
resizeObserver.disconnect()
delete wrapperRef.current[SYMBOL_OBSERVER_KEY]
}
}, [])
return (
<>
<Wrapper
{...props}
// 绑定的唯一标识
data-br={id}
data-brr={ratio}
ref={wrapperRef}
style={{
display: 'inline-block',
verticalAlign: 'top',
textDecoration: 'inherit',
}}
suppressHydrationWarning
>
{children}
</Wrapper>
{createScriptElement(hasProvider, `self.${SYMBOL_KEY}("${id}",${ratio})`)}
</>
)
}
通过上面的源码分析,主要的动态计算逻辑都在relayout函数中
const relayout: RelayoutFn = (id, ratio, wrapper) => {
// 根据id获取包裹的wrapper组件
wrapper =
wrapper || document.querySelector<WrapperElement>(`[data-br="${id}"]`)
// wrapper的父容器
const container = wrapper.parentElement
// 更新wrapper的最大宽度
const update = (width: number) => (wrapper.style.maxWidth = width + 'px')
// 重置wrapper的最大宽度
wrapper.style.maxWidth = ''
// 获取wrapper的父容器的宽高
const width = container.clientWidth
const height = container.clientHeight
// 二分查找的方式计算wrapper的宽度
let left: number = width / 2
let right: number = width
let middle: number
if (width) {
while (left + 1 < right) {
middle = ~~((left + right) / 2)
update(middle)
if (container.clientHeight === height) {
// 缩放后 高度没有变 那么right= middle
right = middle
} else {
// 否则right = middle
left = middle
}
}
// 更新wrapper的宽度
update(right * ratio + width * (1 - ratio))
}
// 通过ResizeObserver去监听wrapper父容器的变化 执行relayout函数
if (!wrapper['__wrap_o']) {
;(wrapper['__wrap_o'] = new ResizeObserver(() => {
self.__wrap_b(0, +wrapper.dataset.brr, wrapper)
})).observe(container)
}
}