2.1
通过 React 的 Diff 算法比较旧虚拟 DOM 树和新虚拟 DOM 树之间的 Change ,然后批处理这些改变
通过一个例子了解Fiber,可以看到点击切换后先呈现内容后展示切换动画,说明先把优先级高的内容呈现出来,不要让用户等待时间过长(loading界面)。
import { createSignal, Suspense, Switch, Match, useTransition } from "solid-js";
import { render } from "solid-js/web";
import Child from "./child";
import "./styles.css";
const App = () => {
const [tab, setTab] = createSignal(0);
const [pending, start] = useTransition();
const updateTab = (index) => () => start(() => setTab(index));
return (
<>
<ul class="inline">
<li classList={{ selected: tab() === 0 }} onClick={updateTab(0)}>
Uno
</li>
<li classList={{ selected: tab() === 1 }} onClick={updateTab(1)}>
Dos
</li>
<li classList={{ selected: tab() === 2 }} onClick={updateTab(2)}>
Tres
</li>
</ul>
<div class="tab" classList={{ pending: pending() }}>
<Suspense fallback={<div class="loader">Loading...</div>}>
<Switch>
<Match when={tab() === 0}>
<Child page="Uno" />
</Match>
<Match when={tab() === 1}>
<Child page="Dos" />
</Match>
<Match when={tab() === 2}>
<Child page="Tres" />
</Match>
</Switch>
</Suspense>
</div>
</>
);
};
render(App, document.getElementById("app"));
1.Fiber干了啥?
react在render第一次渲染时,会通过React.createElement创建一颗Element树Virtual DOM Tree,同时基于Virtual DOM Tree创建一个结构相同的FiberTree
Virtual DOM Tree 虚拟 DOM 树 虚拟 DOM 树的存在就是为了解决 js 直接操作真实 DOM 而引起的计算机计算能力的浪费。 因为通过 js 直接修改 DOM ,会引起整颗 DOM 树计算和改变,而虚拟 DOM 树的存在可以让真实 DOM 只改变必要改变的部分。
FiberTree是由FiberNode构成的,更像是一个单链表构成的树,便于向上、向下、向兄弟节点转换
组件树和fiber树结构对应,一个组件实例有一个对应的fiber实例、
Fiber负责整个应用层面的调和,fiber实例负责组件的调和。
2.规定调度顺序:expirationTime到期时间
每个FiberNode都会有一个ExpirationTime到期时间来确定当前时间片是否执行该节点的更新任务。
到期时间越短,优先级越高。
为了防止某个Update因为优先级的原因一直被打断而未能执行。React会设置一个ExpirationTime,如果到了这个时间某个Update还未执行的话,React将会强制执行该update,这就是ExpirationTime的作用。
每一次update之前检查
WillMount任务优先级比较低(找哪些节点挂载到界面中),有可能会被高优先级(render、
DidMount )任务打断,打断之后会重新再执行一次,执行次数多了就失去了唯一性,不够安全
componentDidMount:
成功render并渲染完成真实DOM之后触发,可以修改DOM
用来放一些请求,订阅函数调用,setInterval,基于创建完的dom进行初始化
render:只能访问this.props和this.state,不允许修改状态和DOM输出
2.2 事件、state与setState
把要更新的值都放在state里,更新数值用setState
仅仅更改数值并不能在界面上直接显示出来,所以需要state
import React from 'react'
export default function App2() {
state={
num:1
}
return (
<div>
<h2>数字为:{this.state.num}</h2>
<button onClick={()=>this.setState({num:this.state.num+1})}></button>
</div>
)
}
对类的复习
若A类继承了B类 且A中写了构造器 那么A类构造器中的super是必须要调用的
类中所定义的方法 都是放在原型对象中的 供实例对象去使用
setState的三种写法
useState
第一个参数,第二个放用来修改参数的方法
函数式组件
函数式组件没有生命周期
函数式组件没有this
函数式组件没有state状态
2.3受控组件与不受控组件
不受控组件:
和组件本身state数据没有关系,所以不受组件管理
受控组件:
表单元素的value值受组件state数据控制,表单中有onChange事件,可以在事件中对表单做实时验证,验证是否合法然后做相应操作
2.4 传值、父传子、子传父
无论是父传子还是子传父,真正在做事的都是父组件,即使是子传父,也是父组件给子组件提供了一个方法来实现的。
父传子
以属性的形式传给组件即可
let msg = "你好世界"
export default function App(){
return <Sub msg={msg} />
}
// 子组件
export default function Sub(props) {
return <h2>{props.msg}</h2>
}
子传父
export default function App(){
const fn = function(arg){
console.log(arg) // 123
}
return <Sub msg={msg} fn={fn} />
}
// 子组件
export default function Sub(props) {
return (
<>
<h2>{props.msg}</h2>
<button onClick={()=>props.fn(123)}>将123传递给父组件</button>
</>
)
}
this.state
先在state里面定义 之后再使用
// 定义状态数据:
constructor(props){
super(props)
this.state = {
num: 20
}
}
// 使用状态数据:
return (
<div>
<p>{this.state.num}</p>
</div>
)