学习react

React元素是创建的开销极小的普通对象。ReactDOM会负责更新DOM来与React元素保持一致。

元素描述了你在屏幕上看到的内容

const element = <h1>Hello World</h1>

仅使用React创建的应用通常只有单一的根dom节点。如果你在将react集成进一个已有应用,那么你可以在应用中包含任意多个独立的根dom节点。

React元素是不可变对象。一旦被创建,就无法更改它的子元素或者属性。一个元素就像是电影里的单帧:它代表了某个特定时刻的UI。
根据我们已有的知识,更新UI的唯一方式是创建一个全新的元素,并将其传入ReactDOM.render().

尽管每一秒我们都会新创建一个描述整个ui树的元素,reactDOM只会更新实际改变了的内容。考虑UI在任意给定时刻的状态,而不是随时间变化的过程,能够消灭一整类的bug.(此处是在diss Vue吗)

组件和Props

组件允许你将UI拆分为独立可复用的代码片段,并对每个片段进行独立构思。

组件:类似于函数,接受任意的入参,返回用于描述展示内容的React元素。

建议从组件自身的角度命名props,而不是依赖调用组件的上下文命名。

Props的只读性

组件无论是使用函数声明还是通过class声明,都不能修改自身的props。

在不违反此规则的情况下,state允许react组件随用户的操作、网络响应或者其他变化而动态的更改输出的内容。

State和生命周期

State与porps类似,但是state是私有的,并且完全受控于当前组件。

每次组件更新的时候render方法都会被调用。只要在相同的DOM节点中渲染,就仅有一个Clock组件的class实例被创建使用。

Class组件应该始终使用props参数来调用父类的构造函数。

在具有许多组件的应用程序中,当组件被销毁时释放所占用的资源是非常重要的。

当Clock组件第一次被渲染到DOM中的时候,就为其设置一个计时器,这在React中被称为“挂载”,同时当DOM中Clock组件被删除的时候,应该清除计时器,这在react中被称为‘卸载’。我们可以为class组件声明一些特殊的方法,当组件挂载或卸载时就会去执行这些方法。

这些方法叫做“生命周期方法”,componentDidMount()方法会在组件已经被渲染到DOM中后运行,所以最好在这里设置计时器。

尽管this.props和this.state是react本身设置的,且都拥有特殊的含义,但是我们可以向class中随意添加不参与数据流的额外字段。

比如计时器ID

this.timerID = setInterval(() => this.tick(), 1000);

使用this.setState()来时刻更新组件state:

当clock的输出被插入到DOM后,React就会调用componentDidMount()生命周期方法。

State的更新可能是异步的

this.setState((state, props) => {
    counter: state.counter + this.props.increment
});

这个函数用上一个state作为第一个参数,将此次更新被应用时的porps做为第二个参数。

数据瀑布

受控组件

由于在表单元素上设置了 value 属性,因此显示的值将始终为 this.state.value,这使得 React 的 state 成为唯一数据源。由于 handlechange 在每次按键时都会执行并更新 React 的 state,因此显示的值将随着用户输入而更新。

总的来说,这使得input textarea select之类的标签都非常相似,它们都接受一个value属性,可以通过value来实现受控组件。

可以将数组传递到value属性中,以支持在select标签中选择多个选项。

打包📦是一个将文件引入并合并到一个单独文件的过程,最终形成一个’bundle’.接着在页面上引入该bundle,整个应用即可一次性加载。

代码分割

import {add} from './math';

console.log(add(16,26));

// =>

import('./math').then(math => {
    console.log(math.add(16, 26))
});

异常捕获边界

context

const ThemeContext = React.createContex('light');

class App extends React.Component {
    render() {
        return (
            <ThemeContext.Provider value="dard">
                <Toolbar />
            </ThemeContext.Provider>
        )
    }
}

如此中间的组件再也不用指明往下传递theme了。

一种无需context的解决方案,是将Avatar自身传递下去,因而中间组件无需知道user或者avatarSize等props

当react渲染了一个订阅了这个context对象的组件,这个组件会从组件树中离自己最近的那个匹配的Provider中读取到当前的context值。只有当组件树中没有匹配到Provider时,其默认参数才会生效。

Provider 接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。

当Provider的value值发生变化时,它内部的所有消费者组件都会重新渲染。Provider及其内部的consumer组件都不受控于shouldComponentUpdate函数,因此当consumer组件在其祖先组件退出更新的情况下也能更新。

Class.contextType

挂载在class上的contextType属性会被重新赋值为一个由React.createContext()创建的context对象。

错误边界

部分UI的js错误不应该导致整个应用崩溃,为了解决这个问题react16引入了一个新的概念—-错误边界。

只有class组件才能成为错误边界组件。大多数情况下只需要声明一次错误边界,并在整个应用中使用它。

事件处理器不会在渲染期间触发,因此如果他们跑出异常。

如果你需要在事件处理器内部捕获错误,使用普通的js try / catch 语句。

Refs和DOM

下面几个适合使用refs的情况:

  • 管理焦点、文本选择或媒体播放
  • 触发强制动画
  • 集成第三方dom库

避免使用refs来做任何可以通过声明式实现来完成的事情

🌰:避免在Dialog组件里暴露open和close方法,最好传递isOpen属性

Render Props

是指一种在react组件之间使用一个值为函数的props共享代码的简单技术

高阶组件

hoc是react中用于复用组件逻辑的一种高级技巧。hoc自身不是reactapi的一部分,它是一种基于react的组合特性而形成的设计模式

具体而言,高阶组件是参数为组件,返回值为组件的函数。

组件是将prps转化为ui,而高阶组件是将组件转化为另一个组件

hoc在react的第三方库中很常见,例如redux的connet和Relay的createFragmentContainer.

之前react建议使用mixins用于解决横切关注的问题,但是后来意识到mixins会产生更多麻烦。

hoc不会修改传入的组件,也不会使用继承来复制其行为。相反,hoc将通过将组件包装在容器组件中来组成新的组件。hoc是纯函数,没有副作用。

函数签名

定义了函数或者方法的输入与输出。

签名可以包含以下内容;

  • 参数与参数的类型
  • 一个返回值及其类型
  • 可能会抛出或传回的异常
  • 方法在面向对象程序中的可用性方面的信息(public、static或者prototype)

connect是一个返回高阶组件的高阶函数。

不应该在组件的render方法中对一个组件使用hoc:

重新挂载组件会导致组件及其所有的子组件的状态丢失。

ref实际上并不是一个prop就像key一样,它是由react专门处理的。如果将ref添加到hoc的返回组件中,则ref引用指向容器组件,而不是被包装组件。

React可以被用于任何web应用中,可以被嵌入到其他应用,其他应用也可以被嵌入到react.

React不会理会React自身之外的dom操作。

深入jsx

实际上jsx仅仅只是React.createElement(component, props, …children)函数的语法糖。

js表达式作为props

可以把包裹在{}中的js表达式作为一个props传递给jsx元素。

注意: if 语句以及for循环不是js表达式,所以不能在jsx中直接使用。

props默认值是true,如果你没给props赋值,它的默认值是true.

包含在开始和结束标签之间的jsx表达式内容将作为特定属性props.children传递给外层组件。

React组件可以返回存储在数组中的一组元素:

render() {
    return [
        <li key="A">A</li>
        <li key="B">B</li>
        <li key="C">C</li>
    ]
}