最后更新:2021-04-03
上次更新:2021-03-16
创建时间:2020-09-03
一直没有时间来写一篇长长的笔记(我想起我的几十篇AWS笔记已经放了一年多了还没整理/(ㄒoㄒ)/~~),之前折腾React
和React Native
的时候,也是需要用到哪儿看到哪儿或者Google搜索知识,并没有太多时间去看看,加上React
和React Native
升级频繁,常常弃用各种,所关联的一些成熟组件也有些坑。尤其是React Native
的一些轮子,每次升级不如推翻重写,要人老命(这我在博客中抱怨过很多次)。
前一段时间(大半年,去年吧)抽空一页页温习了最新的React文档(目前最新版本为17.1),用Onenote
顺便记录了一二。时间久了,又忘记了差不多了,晚上花时间稍微梳理了一下。
姑且把笔记贴出来,作为勉励。扫了一下,很多已经忘记了。
注:代码在Onenote里面对齐好了,贴这里没对齐了,算了,懒得整了。
- 1.State
- 2.事件绑定
- 3.Key值指定位置
- 4.数据流
- 5.没有slot,当数据传递就行了
- 6.Fragment
- 7.现成的打包框架
- 8.懒加载
- 9.Context 全局
- 10.错误边界
- 11.高阶组件(HOC) [重要]
- 12.深入JSX
- 13.性能优化
- 15.Portal
- 16.Profiler
- 17.Refs
- 18.render prop [重要]
- 19.静态类型检查
- 20.严格模式
- 21.非受控组件
- 22.Hook [重要]
- 23.测试
1.State
// Correct
this.setState({comment: 'Hello'});
构造函数是唯一可以给 this.state 赋值的地方
关联文章:do-not-modify-state-directly
SetState是异步的,这里有讲解为什么要这么做:
关联文章:faq-state
如果确实需要依赖上一步的state数据,则需要将state传递进来:
incrementCount() {
this.setState((state) => {
// 重要:在更新的时候读取 `state`,而不是 `this.state`。
return {
count: state.count + 1}
});
}
handleSomething() {
// 假设 `this.state.count` 从 0 开始。
this.incrementCount();
this.incrementCount();
this.incrementCount();
// 如果你现在在这里读取 `this.state.count`,它还是会为 0。
// 但是,当 React 重新渲染该组件时,它会变为 3。
}
不使用同步的原因:
这样会破坏掉 props 和 state 之间的一致性,造成一些难以 debug 的问题。
这样会让一些我们正在实现的新功能变得无法实现。
2.事件绑定
1> 构造函数时绑定
constructor this.handleClick = this.handleClick.bind(this);
handleClick() {
console.log('this is:', this);
}
<div onClick={this.handleClick}>
2> 箭头函数绑定1
// 注意: 这是 实验性 语法。
handleClick = () => { console.log('this is:', this); }
<div onClick={this.handleClick}>
3> 箭头函数绑定2
handleClick = { console.log('this is:', this); }
<div onClick={()=>this.handleClick()}>
通常情况下,如果你没有在方法后面添加 (),例如 onClick={this.handleClick},你应该为这个方法绑定 this。
关联文章:handling-events
3.Key值指定位置
如果你提取出一个 ListItem 组件,你应该把 key 保留在数组中的这个
function ListItem(props) {
// 正确!这里不需要指定 key:
return <li>{props.value}</li>;
}
const listItems = numbers.map((number) =>
// 正确!key 应该在数组的上下文中被指定
<ListItem key={number.toString()} value={number} />
);
跟Vue
类似了,我记得老版本是不需要key
的。
关联文章:lists-and-keys
key 会传递信息给 React ,但不会传递给你的组件。如果你的组件中需要使用 key 属性的值,请用其他属性名显式传递这个值:
const content = posts.map((post) =>
<Post
key={post.id} id={post.id} title={post.title} />
);
4.数据流
你应当依靠自上而下的数据流,而不是尝试在不同组件间同步 state。
写fleece
时发现组件太多要命,引入redux
,还要啥父子之间传值😂
关联文章:lifting-state-up
5.没有slot,当数据传递就行了
说实话,在Vue
中比较讨厌slot
的写法
关联文章:composition-vs-inheritance
6.Fragment
类似VueJS
里面的template
,不占用Dom元素位置
import React, { Fragment } from 'react';
function ListItem({ item }) {
return (
<Fragment>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</Fragment>
);
}
假如不需要在 fragment 标签中添加任何 prop 且你的工具支持的时候,例如:key等。可以使用短语法:
<>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</>
关联文章:accessibility
7.现成的打包框架
CLI
很方便生成基础代码,和Vue
一样
Webpack : Create React App,Next.js,Gatsby,
8.懒加载
React.lazy
使用之前:
import OtherComponent from './OtherComponent';
使用之后:
const OtherComponent = React.lazy(() => import('./OtherComponent'));
Vue
中可以类似这种用法
感觉可以在这里加入骨架图,详见这里的loading:
https://zh-hans.reactjs.org/docs/code-splitting.html
路由切换过渡效果
9.Context 全局
例如本地化,主题(locale,theme),不太可能通过prop一个个组件传递每个子组件
关联文章:context
10.错误边界
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染能够显示降级后的 UI
return { hasError: true };
}
Render判断state的hasError属性就行了
或者自己使用常规组件,生命周期中自己定义状态try/catch也可以完成
关联文章:error-boundaries
11.高阶组件(HOC) [重要]
[1]
这是个很重要的功能,这里建议参考掘金上的这篇文章:React 高阶组件(HOC)入门指南
官方给出说即使不使用高阶组件也能实现所有的功能,所以如果懒,不看这里也够用。
12.深入JSX
1> prop的默认值是true,不设置就是true,但是建议要赋值。
关联文章:jsx-in-depth-props-default-to-true
13.性能优化
1> 使shouldComponentUpdate
简单判断返回true/false
来决定组件是否重新渲染,
2> 或者组件直接继承 class CounterButton extends React.PureComponent
class XXComponent extends React.PureComponent {
// todo
}
注意:上面仅是浅比较,所以当 props 或者 state 某种程度是可变的话,浅比较会有遗漏
15.Portal
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。
ReactDOM.createPortal(child, container)
关联文章:portals
16.Profiler
性能分析
关联文章:profiler
关联文章:introducing-the-react-profiler
结合Chrome
17.Refs
尽量要用数据来代替,
a.为DOM添加refs:
跟Vue
类似
Refs 是使用 React.createRef() 创建的,创建的 ref 接收底层 DOM 元素作为其 current 属性: this.textInput.current.focus();
关联文章:adding-a-ref-to-a-dom-element
b.为Class添加refs:
this.textInput.current.focusTextInput();
关联文章:adding-a-ref-to-a-class-component
ref 转发。Ref 转发使组件可以像暴露自己的 ref 一样暴露子组件的 ref
c.String 类型的 Refs:
this.refs.textInput 来访问 DOM 节点,这种将在未来版本中移除
d.会接收到两次数据,第一次为null,除非转化为Class组件,当然无关紧要
18.render prop [重要]
render prop 是一个用于告知组件需要渲染什么内容的函数 prop
关联文章:render-props
[2]
关于Render props
的文章可以看这一篇就足够了,[译] 使用 Render props 吧!
19.静态类型检查
1>Flow和typescript
Create React App 自带
TS支持的类型检查可以这样添加:
npx create-react-app my-app –template typescript
2> react 内置的类型检查
要在组件的 props 上进行类型检查,你只需配置特定的 propTypes 属性:
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
defaultProps 默认值
使用常见的数据类型,也可以自定义验证方法
关联文章:typechecking-with-proptypes
20.严格模式
<React.StrictMode>
//todo
</React.StrictMode>
新的 context API 文档: context
关联文章:strict-mode
21.非受控组件
<input defaultValue="Bob" type="text" ref={this.input} />
<input type="checkbox">
和 <input type="radio">
支持 defaultChecked,<select>
和 <textarea>
支持 defaultValue。
偶然发现这里博客有bug,解析markdown的坑😭,懒得修主题了。
22.Hook [重要]
[3]
Hook 是 React 16.8新增特性。
Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。
官方说现在阶段是过度,可以使用class/hook,不用为了hook将所有的class迁移过去。并且class也不会废除,都可以使用。
在以外的组件中,分为函数组件
和class组件
两种,class组件
可以用setState
保存用户状态,有完整的生命周期,但是也有缺陷,不利于代码压缩,当项目庞大时组件过多会导致密密麻麻混乱的状态,导致无法管理,但是函数组件
又无法使用setState
来保存状态,这个时候,hook
诞生了。(2021-04-03 更新)
准确的说,hook
是为了解决函数组件
中状态的问题。(2021-04-03 更新)
1> useState
你可以在一个组件中多次使用 State Hook:
function ExampleWithManyStates() {
// 声明多个 state 变量!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
// ...
}
数组结构语法: let [a,b]=[2,3];console.log(a);//2
数组解构:
const [count, setCount] = useState(0);
const [fruit, setFruit] = useState('banana');
等价于:
var fruitStateVariable = useState('banana'); // 返回一个有两个元素的数组
var fruit = fruitStateVariable[0]; // 数组里的第一个值
var setFruit = fruitStateVariable[1]; // 数组里的第二个值
关联文章:estructuring_assignment#Array_destructuring
2> useEffect
useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。
// 相当于 componentDidMount 和 componentDidUpdate:
useEffect(() => {
// 使用浏览器的 API 更新页面标题
document.title = `You clicked ${count} times`;
});
useEffect 做了什么? 通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。
React 会在每次渲染后调用副作用函数 —— 包括第一次渲染的时候
只能在 React 的函数组件中调用 Hook, 不要在循环、条件判断或者子函数中调用.
函数组件
复习一下, React 的函数组件是这样的:
const Example = (props) => {
// 你可以在这使用
Hook
return <div />;
}
或是这样:
function Example(props) {
// 你可以在这使用
Hook
return <div />;
}
Hook 在 class 内部是不起作用的。但你可以使用它们来取代 class
3.use
自定义 Hook 必须以 “use” 开头吗?必须如此。这个约定非常重要。不遵循的话,由于无法判断某个函数是否包含对其内部 Hook 的调用,React 将无法自动检查你的 Hook 是否违反了 Hook 的规则。
多次调用状态独立,不会共享。
Hook 本身就是函数
useState 并不会使得集中更新逻辑变得容易,因此你可能更愿意使用 redux 中的 reducer 来编写。
4.Class迁移到Hook
生命周期方法要如何对应到 Hook?
constructor:函数组件不需要构造函数。你可以通过调用 useState 来初始化 state。如果计算的代价比较昂贵,你可以传一个函数给 useState。
getDerivedStateFromProps:改为 在渲染时 安排一次更新。
shouldComponentUpdate:详见 下方 React.memo.
render:这是函数组件体本身。
componentDidMount, componentDidUpdate, componentWillUnmount:useEffect Hook 可以表达所有这些(包括 不那么 常见 的场景)的组合。
getSnapshotBeforeUpdate,componentDidCatch 以及 getDerivedStateFromError:目前还没有这些方法的 Hook 等价写法,但很快会被添加。
关联文章:how-do-lifecycle-methods-correspond-to-hooks
23.测试
关联文章:testing-recipes