📒 推荐使用 stylus
推荐使用 stylus,所有的 {}
、:
以及 ;
都是可省略的:
.page
padding-bottom 2rem
display block
.content-lock
display none
text-align center
padding 2rem
font-size 1em
这就类似为什么建议使用
yaml
替代json
,在yaml
中不需要引号,简单省事
📒 页面性能优化技巧
分析代码执行耗时可以通过 火焰图,分析内存占用情况可以通过 堆快照。
⭐️ react-use - 一个 React Hooks 库
📒 Next.js 提供的渲染方式
- SSR: Server-side rendering (服务端渲染)
- SSG: Static-site generation (静态站点生成)
- CSR: Client-side rendering (客户端渲染)
- Dynamic routing (动态路由)
- ISR: Incremental Static Regeneration (增量静态再生)
CSR、SSR、SSG 的区别?
CSR 是在用户浏览器端调接口请求数据进行渲染;SSR 是在用户请求页面的时候,服务器端请求数据并进行渲染;SSG 是直接在构建阶段就进行渲染,一般用于文档网站。
📒 Node 案发现场揭秘 —— 未定义 “window” 对象引发的 SSR 内存泄露
📒 如何实从零实现 husky
看下如何做 测试驱动开发
📒 如何让一个构造函数只能用 new
调用
使用 ES6 class 会检查是否通过 new
调用,而普通构造函数不会检查是否通过 new
调用,这种情况下需要手动进行判断,通常都会这样做:
function MyClass() {
if (!(this instanceof MyClass)) {
throw new Error("MyClass must call with new");
}
// ...
}
这样的话,如果不通过 new
调用,就会抛出异常。其实更好的方案是进行兼容处理,即不使用 new
调用,自动改用 new
调用:
function MyClass() {
if (!(this instanceof MyClass)) {
// 如果没有使用 `new` 调用,自动改用 `new` 调用
// 通过 `return` 中断函数执行,并返回创建的实例
return new MyClass();
}
// ...
}
📒 为什么 React Hook 底层使用链表而不是数组
📒 React 17 架构
📒 数组的 flatMap
方法
数组的 [].map()
可以实现一对一的映射,映射后的数组长度与原数组相同。有时候需要过滤掉一些元素,或者实现一对多的映射,这时候只用 map
就无法实现了。这种情况下就可以使用 flatMap
:
// 需要过滤掉 0,并且使其余各元素的值翻倍
const numbers = [0, 3, 6];
// 常规方法是 map 和 filter 搭配
const doubled = numbers
.filter(n => n !== 0)
.map(n => n * 2)
// 使用 flatMap 实现
const doubled = numbers.flatMap(number => {
return number === 0 ? [] : [2 * number];
})
此外还可以实现一对多的映射:
const numbers = [1, 4];
const trippled = numbers.flatMap(number => {
return [number, 2 * number, 3 * number];
})
console.log(trippled); // [1, 2, 3, 4, 8, 12]
flatMap
实际上是先 map
再 flat
,理解了这一点就能掌握了
📒 V8 Promise源码全面解读,其实你对Promise一无所知
⭐️ 如何编写更好的 JSX 语句
查看详情
列表不为空的时候进行渲染:
// 注意这种写法有 bug
// 如果 data 数组为空,则会直接渲染 `0` 到页面上
{data.length && <div>{data.map((d) => d)}</div>}
// 使用 && 的时候需要手动转换布尔值
data.length > 0 && jsx
!!data.length && jsx
Boolean(data.length) && jsx
不要使用 props
传递的 React 元素作为判断条件:
// 这样的判断不准确
// props.children 可能是一个空数组 []
// 使用 children.length 也不严谨,因为 children 也可能是单个元素
// 使用 React.Children.count(props.children) 支持单个和多个 children
// 但是对于存在多个无效节点,例如 false 无法准确判断
// 使用 React.Children.toArray(props.children) 可以删除无效节点
// 但是对于一个空片段,例如 <></> 又会被识别为有效的元素
// 所以为了避免出错,建议不要这样判断
const Wrap = (props) => {
if (!props.children) return null;
return <div>{props.children}</div>
};
重新挂载还是更新:
// 使用三元运算符分支编写的 JSX 看上去就像完全独立的代码
{hasItem ? <Item id={1} /> : <Item id={2} />}
// 但实际上 hasItem 切换时,React 仍然会保留挂载的实例,然后更新 props
// 因此上面的代码实际上等价于下面这样
<Item id={hasItem ? 1 : 2} />
// 一般来讲不会有什么问题,但是对于非受控组件,就可能导致 bug
// 例如 mode 属性变化,会发现之前输入的信息还在
{mode === 'name'
? <input placeholder="name" />
: <input placeholder="phone" />}
// 由于 React 会尽可能复用组件实例
// 因此我们可以传递 key,告诉 React 这是两个完全不一样的元素,让 React 强制重新渲染
{mode === 'name'
? <input placeholder="name" key="name" />
: <input placeholder="phone" key="phone" />}
// 或者使用 && 替代三元运算符
{mode === 'name' && < input placeholder = "name" /> }
{mode !== 'name' && < input placeholder = "phone" /> }
// 相反,如果在同一个元素上的逻辑条件不太一样
// 可以试着将条件拆分为两个单独的 JSX 提高可读性
<Button
aria-busy={loading}
onClick={loading ? null : submit}
>
{loading ? <Spinner /> : 'submit'}
</Button>
// 可以改为下面这样
{loading
? <Button aria-busy><Spinner /></Button>
: <Button onClick={submit}>submit</Button>}
// 或者使用 &&
{loading && <Button key="submit" aria-busy><Spinner /></Button>}
{!loading && <Button key="submit" onClick={submit}>submit</Button>}