什么是 React 的状态(state)
- React 的状态 state 是一个对象
- 类组件中,状态通过
this.state
创建,通过this.setState
合并更改,异步更新 - React Hook 中,状态通过
this.useState
或this.useReducer
使用
- 类组件中,状态通过
- React 将组件看做状态机,状态改变触发渲染
- React 建议减少有状态的组件,提高组件复用度,利于维护
- 只将无法从 props 传递,无法从其他数据计算,并且随时间可能变化的数据作为 state
- 多个组件 state 的数据源相同,应将状态提升到父组件或容器组件
- 避免使用 context,仅在 React 的状态管理无法满足需求时使用 Redux
什么是 React 的状态提升
- React 中,任何可变数据应当只有一个相对应的唯一“数据源”
- 多个组件反映相同的变化数据时,共享状态提升到最近的共同父组件
- state 应首先添加到需要渲染数据的组件
- 其他组件也需要这个 state,将它提升至这些组件的最近共同父组件
- state 只能由拥有它们的组件修改,bug 排查范围被大大缩减
状态(state)和属性(props)的区别是什么
相同点
- state 和 props 都是原生的 JavaScript 对象,在 React 中代表了组件的数据来源
- state 和 props 的变化都会触发生命周期钩子 componentWillUpdate、useEffect / useLayoutEffect、和渲染
- 同样的 state/props 渲染结果相同
- state 和 props 都可以在组件内部设置默认值
不同点
- 获取
- state 由当前组件声明
- props 由父组件传入
- 更新
- state
- 由所在组件通过 useState / useReducer 或 setState 方法更新
- 由子组件通过传入的 props 中的回调函数间接更新
- props 不允许修改
- state
- 数据
- state 通常存储组件相关的可变数据,避免多层嵌套或使用不可变对象便于优化渲染
- props 除数据外,还多用于回调函数,组件(children),路由(history)的传递
- 获取
setState 和 replaceState 的区别
- setState 会合并当前状态与之前状态
- replaceState 会丢弃之前状态,用新状态替代
- replaceState 等同于先在 setState 中将状态设置为 false / null,再设置新状态
如何优化 setState,减少不必要更新
- 通过
setState(updater, [callback])
的用法,第一参数使用带有形式参数的函数 - 通过 updater 函数
(state, props) => stateChange
的第一参数,接受原来的 state 状态值 - 对比新旧状态值
- 相同,返回 null,不渲染
- 不同,返回新状态值,触发异步合并渲染
示例代码:1
2
3
4
5
6getData = data => {
const { time } = data
this.setState(state => {
return state.time === time ? null : { time }
})
}
当 state 值为 Object 时,如何优化
- 避免使用 Object 作为 state 值,使用 PureComponent 的浅比较的自动优化失效
- 必需使用 Object 作为 state 值
- 避免嵌套过多层级
- 设置更新 state 的前置条件或使用 shouldComponentUpdate 手动优化
- 已经使用 Object 作为 state 值,并且嵌套层级过多
- 拆分 state 到子组件
- 使用不可变对象 Immutable,只要 state 更新,返回对象新引用,重新渲染修改节点
什么是 React 的属性(props)
- 属性是组件的入参,用法同 HTML 自定义属性,可将任意类型数据从父组件传给子组件
- 属性的改变可以触发组件的生命周期流程和渲染
- 建议从组件自身的角度,不依赖于调用中间的上下文命名 props
- 属性具有只读性,所有 React 组件必须像纯函数一样保护它们的 props 不被更改
- 请避免使用匿名函数作为属性值,避免引起重复渲染
- 具有 render prop 的组件接受一个返回 React 元素的函数,并在组件内部通过调用此函数来实现自己的渲染逻辑
为什么不能直接修改属性(props)
- React 仅支持单向数据流,数据通过 props 由外向内传递
- 从 state 派生数据或 UI 只能影响“低于”它们的组件,设计简单高效,便于调试
- 所有 React 组件必须像纯函数一样保护它们的 props 不被更改,保证组件没有副作用
通过属性(props)传递组件本身的方法有哪些
- props.children
- 子组件可以获取父组件开始标签和结束标签之间的内容
- render props
- 向子组件传入函数,返回组件需要渲染什么内容
- 直接在父组件的标签之间,调用函数返回组件
- 避免使用匿名函数返回组件,避免重复渲染
使用 key 属性有哪些注意事项
- key 用来帮助 React 识别数组列表中哪些元素改变了,从而更好的更新元素
- key 在数组列表及兄弟节点之间必须唯一
- 不建议使用索引作为 key 值,如果不显示指定 key 值,默认使用索引作为 key 值
- key 只有放在就近的数组上下文中才有意义
- key 不会传递给子组件,需要使用 key 属性的值,需使用其他属性显式传递
如何在 React 中进行静态类型检查
- React.PropTypes 或 prop-types 库
- 提供一系列验证器,确保组件接收到的数据类型有效
- PropTypes 仅在开发模下进行检查并在控制台显示警告
- 通过特定的 defaultProps 属性来定义 props 的默认值
- Flow
- Flow 是一个针对 JavaScript 代码的静态类型检测器
- 由 Facebook 开发,经常与 React 一起使用
- Flow 通过特殊类型语法为变量、函数以及 React 组件提供注解
- Flow 添加方法
- 将 Flow 添加到项目依赖
- 确保编译后的代码已经去除 Flow 语法
- 添加类型注解并且运行 Flow 来检查
- TypeScript
- TypeScript 是微软开发的编程语言,它是 JavaScript 的类型超集,包含独立编译器
- 强类型语言,构建时可以发现 bug 和错误
- TypeScript 添加方法
- 将 TypeScript 添加到项目依赖
- 配置 TypeScript 编译选项
- 使用正确的文件扩展名,React 的 JSX 使用.tsx作为扩展名
- 为已经使用的库添加定义,现实其他包的错误和提示
React 是否支持原生 HTML 属性
- 任何标准和自定义的 DOM 属性都是完全支持的
- React 为 DOM 提供了一套以 JavaScript 为中心的 API
- 标准 DOM 属性采用小驼峰命名
- 自定义属性全部小写
- React 与 HTML 之间部分属性存在差异
- checked
- 受控组件 checked
- 非受控组件用 defaultChecked 设置组件首次挂载时是否被选中
- className
- 用于指定 DOM 节点和 SVG 元素的 class
- React 中,使用 Web Components,使用 class 属性代替
- dangerouslySetInnerHTML
- React 为浏览器 DOM 提供 innerHTML 的替换方案
- 需要向该属性传入 key 为 __html 的对象,用来警示跨站脚本(XSS)攻击风险
- htmlFor
- for 是 JavaScript 关键字,React 元素使用 htmlFor 代替
- onChange
- onChange 事件与预期行为一致:表单字段变化时,事件都会被触发
- 与浏览器已有的默认行为不一致:
- 用户更改
<input>
,<select>
和<textarea>
元素的值并提交更改时 change 事件在这些元素上触发 - 与 input 事件不一样,change 事件不是每次元素的 value 改变时都会被触发
- 用户更改
- React 依靠该事件实时处理用户输入
- selected
- 将
<option>
标记为已选中状态,请在 select 的 value 中引用该选项的值
- 将
- style
- 接受小驼峰命名属性的 JavaScript 对象,而不是 CSS 字符串
- 与 JavaScript 属性一致,同时会更高效,且能预防跨站脚本(XSS)的安全漏洞
- 样式不会自动补齐浏览器私有前缀,除 ms 外,浏览器引擎前缀都应以大写字母开头
- React 自动添加 “px” 后缀到内联样式为数字的属性,本来没有单位的属性 zoom,order,flex 不会转换像素字符串
- 需使用 “px” 以外单位,请将值设为数字与所需单位组成的字符串
- suppressContentEditableWaring
- 禁止拥有子节点的元素比标记为 contentEditable 时 React 发出警告
- suprressHydrationWarning
- 禁止 React 服务端渲染与客户端渲染不同内容时发出警告
- 只会对元素一级深度有效,应急方案使用,不过过度使用
- value
<input>
,<select>
,<textarea>
组件支持 value 属性- 非受控组件使用 dafaultValue 属性设置组件第一次挂载时的 value
- checked