React
react VR
webVR ract-vr、aframe
webgQL
setState的问题
setState是异步更新
setState循环调用风险
当调用setState时,实际上会执行enqueueSetState方法,并对partialState以及pending-StateQueue更新队列进行合并操作,最终通过enqueueUpdate执行state更新
而performUpdateIfNecessary方法会获取_pendingElement, pendingStateQueue,_ pending-ForceUpdate,并调用receiveComponent和updateComponent方法进行组件更新
如果在shouldComponentUpdate或者componentWillUpdate方法中调用setState,此时this._pending-StateQueue != null,就会造成循环调用,使得浏览器内存占满后崩溃
调用栈
既然setState最终是通过enqueueUpdate执行state更新,那么enqueueUpdate到底是如何更新state的呢? 首先看下面的问题
1 | import React, { Component } from 'react'; |
上述代码中,4次console.log打印出来的val分别是: 0,0,2 ,3
enqueueUpdate的源码如下(上面流程的第三步)(batching的意思是批量的)
1 | function enqueueUpdate(component){ |
如果isBatchingUpdates为true,则对所有队列中的更新执行 batchedUpdates
方法,否则只把当前组件(即调用了setState的组件)放入dirtyComponents数组中,例子中4次setState调用的表现之所以不同,这里的逻辑判断起了关键作用
前两次调用setState
时 isBatchingUpdates
已经被设置为true,所以没有立即更新,
后两次在setTimeout的 因为没有前置的batchedUpdates,所以立即更新
React 的坑
在 React
应用中,当某个组件的状态发生变化时,它会以该组件为根,重新渲染整个组件子树。
如要避免不必要的子组件的重渲染,你需要在所有可能的地方使用 PureComponent,或是手动实现 shouldComponentUpdate 方法。同时你可能会需要使用不可变的数据结构来使得你的组件更容易被优化。
1 |
|
在 Vue 应用中,组件的依赖是在渲染过程中自动追踪的,所以系统能精确知晓哪个组件确实需要被重渲染。你可以理解为每一个组件都已经自动获得了 shouldComponentUpdate,并且没有上述的子树问题限制。
Vue 的这个特点使得开发者不再需要考虑此类优化,从而能够更好地专注于应用本身。
React生命周期
所有有关生命周期的变量应该放到class里
1 | class Clock extends React.Component { |
- [state]在React.Component里是只读状态,需要改变state里的值要使用this.setState({data:’’})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75class Component<P, S> {
// tslint won't let me format the sample code in a way that vscode likes it :(
/**
* If set, `this.context` will be set at runtime to the current value of the given Context.
*
* Usage:
*
*
* type MyContext = number
* const Ctx = React.createContext<MyContext>(0)
*
* class Foo extends React.Component {
* static contextType = Ctx
* context!: React.ContextType<typeof Ctx>
* render () {
* return <>My context's value: {this.context}</>;
* }
* }
*
*
* @see https://reactjs.org/docs/context.html#classcontexttype
*/
static contextType?: Context<any>;
/**
* If using the new style context, re-declare this in your class to be the
* `React.ContextType` of your `static contextType`.
* Should be used with type annotation or static contextType.
*
*
* static contextType = MyContext
* // For TS pre-3.7:
* context!: React.ContextType<typeof MyContext>
* // For TS 3.7 and above:
* declare context: React.ContextType<typeof MyContext>
*
*
* @see https://reactjs.org/docs/context.html
*/
// TODO (TypeScript 3.0): unknown
context: any;
constructor(props: Readonly<P>);
/**
* @deprecated
* @see https://reactjs.org/docs/legacy-context.html
*/
constructor(props: P, context?: any);
// We MUST keep setState() as a unified signature because it allows proper checking of the method return type.
// See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257
// Also, the ` | S` allows intellisense to not be dumbisense
setState<K extends keyof S>(
state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
callback?: () => void
): void;
forceUpdate(callback?: () => void): void;
render(): ReactNode;
// React.Props<T> is now deprecated, which means that the `children`
// property is not available on `P` by default, even though you can
// always pass children as variadic arguments to `createElement`.
// In the future, if we can define its call signature conditionally
// on the existence of `children` in `P`, then we should remove this.
readonly props: Readonly<P> & Readonly<{ children?: ReactNode }>;
state: Readonly<S>;
/**
* @deprecated
* https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs
*/
refs: {
[key: string]: ReactInstance
};
}
setState
- setState是异步的,如果需要在改变一个值后在执行方法,需要在setState回调的方法里执行。
1 | setState<K extends keyof S>(state: ((prevState: Readonly<S>, props: P) => Pick<S, K> | S) | (Pick<S, K> | S), callback?: () => any): void |
React Hook
1 | import React, { useState } from 'react'; |
在这里,useState 就是一个 Hook (等下我们会讲到这是什么意思)。通过在函数组件里调用它来给组件添加一些内部 state。React 会在重复渲染时保留这个 state。useState 会返回一对值:当前状态和一个让你更新它的函数,你可以在事件处理函数中或其他一些地方调用这个函数。它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并
你之前可能已经在 React 组件中执行过数据获取、订阅或者手动修改过 DOM。我们统一把这些操作称为“副作用”,或者简称为“作用”。
useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。(我们会在使用 Effect Hook 里展示对比 useEffect 和这些方法的例子。)
1 | import React, { useState, useEffect } from 'react'; |
当你调用 useEffect 时,就是在告诉 React 在完成对 DOM 的更改后运行你的“副作用”函数。由于副作用函数是在组件内声明的,所以它们可以访问到组件的 props 和 state。默认情况下,React 会在每次渲染后调用副作用函数 —— 包括第一次渲染的时候。(我们会在使用 Effect Hook 中跟 class 组件的生命周期方法做更详细的对比。)
Hook 使用规则
Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则:
只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。(还有一个地方可以调用 Hook —— 就是自定义的 Hook 中,我们稍后会学习到。)
Vue与React的区别
vue组件分为全局注册和局部注册,在react中都是通过import相应组件,然后模版中引用;
props是可以动态变化的,子组件也实时更新,在react中官方建议props要像纯函数那样,输入输出一致对应,而且不太建议通过props来更改视图;
子组件一般要显示地调用props选项来声明它期待获得的数据。而在react中不必需,另两者都有props校验机制;
每个Vue实例都实现了事件接口,方便父子组件通信,小型项目中不需要引入状态管理机制,而react必需自己实现;
使用插槽分发内容,使得可以混合父组件的内容与子组件自己的模板;
多了指令系统,让模版可以实现更丰富的功能,而React只能使用JSX语法;
Vue增加的语法糖computed和watch,而在React中需要自己写一套逻辑来实现;
react的思路是all in js,通过js来生成html,所以设计了jsx,还有通过js来操作css,社区的styled-component、jss等;而 vue是把html,css,js组合到一起,用各自的处理方式,vue有单文件组件,可以把html、css、js写到一个文件中,html提供了模板引擎来处理。
react做的事情很少,很多都交给社区去做,vue很多东西都是内置的,写起来确实方便一些, 比如 redux的combineReducer就对应vuex的modules, 比如reselect就对应vuex的getter和vue组件的computed, vuex的mutation是直接改变的原始数据,而redux的reducer是返回一个全新的state,所以redux结合immutable来优化性能,vue不需要。
react是整体的思路的就是函数式,所以推崇纯组件,数据不可变,单向数据流,当然需要双向的地方也可以做到,比如结合redux-form,组件的横向拆分一般是通过高阶组件。而vue是数据可变的,双向绑定,声明式的写法,vue组件的横向拆分很多情况下用mixin
作者:ikoala
链接:https://juejin.im/post/5cf495e96fb9a07ef5622025
来源:掘金
Ant Design 实战教程
组件
一是所有 HTML 标签必须是闭合的,如果写成
Hello就会报错。如果是那种没有闭合语法的标签,必须在标签尾部加上斜杠,比如。二是任何 JSX 表达式,顶层只能有一个标签,也就是说只能有一个根元素
一般来说,HTML 原生标签都使用小写,开发者自定义的组件标签首字母大写,比如
shouldComponentUpdate(nextProps, nextState):每当this.props或this.state有变化,在render方法执行之前,就会调用这个方法。该方法返回一个布尔值,表示是否应该继续执行render方法,即如果返回false,UI 就不会更新,默认返回true。组件挂载时,render方法的第一次执行,不会调用这个方法。
static getDerivedStateFromProps(props, state):该方法在render方法执行之前调用,包括组件的第一次记载。它应该返回一个新的 state 对象,通常用在组件状态依赖外部输入的参数的情况。
getSnapshotBeforeUpdate():该方法在每次 DOM 更新之前调用,用来收集 DOM 信息。它返回的值,将作为参数传入componentDidUpdate()方法。
非受控组件
1 |
|
- 看起来,修改 MyInput 中的值不太容易。
对于这种不能直接控制状态的组件,我们称之为“非受控组件”。
受控组件
1 | const MyInput = ({ value = '', onChange }) => ( |
- “受控”与“非受控”两个概念,区别在于这个
组件的状态是否可以被外部修改
。一个设计得当的组件应该同时支持“受控”与“非受控”两种形式,即当开发者不控制组件属性时,组件自己管理状态,而当开发者控制组件属性时,组件该由属性控制。而开发一个复杂组件更需要注意这点,以避免只有部分属性受控,使其变成一个半受控组件。