站点图标 久久日记本

React读书笔记

最后更新:2021-04-03
上次更新:2021-03-16
创建时间:2020-09-03

一直没有时间来写一篇长长的笔记(我想起我的几十篇AWS笔记已经放了一年多了还没整理/(ㄒoㄒ)/~~),之前折腾ReactReact Native的时候,也是需要用到哪儿看到哪儿或者Google搜索知识,并没有太多时间去看看,加上ReactReact Native升级频繁,常常弃用各种,所关联的一些成熟组件也有些坑。尤其是React Native的一些轮子,每次升级不如推翻重写,要人老命(这我在博客中抱怨过很多次)。

前一段时间(大半年,去年吧)抽空一页页温习了最新的React文档(目前最新版本为17.1),用Onenote顺便记录了一二。时间久了,又忘记了差不多了,晚上花时间稍微梳理了一下。

姑且把笔记贴出来,作为勉励。扫了一下,很多已经忘记了。

注:代码在Onenote里面对齐好了,贴这里没对齐了,算了,懒得整了。

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 保留在数组中的这个 元素上,而不是放在 ListItem 组件中的

  • 元素上。
    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的写法

    和 之类的 React 元素本质就是对象(object),所以你可以把它们当作 props,像其他数据一样传递。这种方法可能使你想起别的库中“槽”(slot)的概念,但在 React 中没有“槽”这一概念的限制,你可以将任何东西作为 props 进行传递。

    关联文章: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 
    
    } 
    

    关联文章:optimizing-performance

    注意:上面仅是浅比较,所以当 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 节点,这种将在未来版本中移除

    关联文章:legacy-api-string-refs

    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

  • 退出移动版