什么是 React 的状态(state)

  • React 的状态 state 是一个对象
    • 类组件中,状态通过 this.state 创建,通过 this.setState 合并更改,异步更新
    • React Hook 中,状态通过 this.useStatethis.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 通常存储组件相关的可变数据,避免多层嵌套或使用不可变对象便于优化渲染
      • 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
6
getData = 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