Fiber 是 React 16 中新的协调引擎或重新实现核心算法。它的主要目标是支持虚拟DOM的增量渲染。React Fiber 的目标是提高其在动画、布局、手势、暂停、中止或重用等方面的适用性,并为不同类型的更新分配优先级,以及新的并发原语。
React Fiber 的目标是增强其在动画、布局和手势等领域的适用性。它的主要特性是增量渲染:能够将渲染工作分割成块,并将其分散到多个帧中。
(1)原理 Redux源码主要分为以下几个模块文件
const actionTypes = {
ADD: 'ADD',
CHANGEINFO: 'CHANGEINFO',
}
const initState = {
info: '初始化',
}
export default function initReducer(state=initState, action) {
switch(action.type) {
case actionTypes.CHANGEINFO:
return {
...state,
info: action.preload.info || '',
}
default:
return { ...state };
}
}
export default function createStore(reducer, initialState, middleFunc) {
if (initialState && typeof initialState === 'function') {
middleFunc = initialState;
initialState = undefined;
}
let currentState = initialState;
const listeners = [];
if (middleFunc && typeof middleFunc === 'function') {
// 封装dispatch
return middleFunc(createStore)(reducer, initialState);
}
const getState = () => {
return currentState;
}
const dispatch = (action) => {
currentState = reducer(currentState, action);
listeners.forEach(listener => {
listener();
})
}
const subscribe = (listener) => {
listeners.push(listener);
}
return {
getState,
dispatch,
subscribe
}
}
(2)工作流程
通俗点解释:
以 store 为核心,可以把它看成数据存储中心,但是他要更改数据的时候不能直接修改,数据修改更新的角色由Reducers来担任,store只做存储,中间人,当Reducers的更新完成以后会通过store的订阅来通知react component,组件把新的状态重新获取渲染,组件中也能主动发送action,创建action后这个动作是不会执行的,所以要dispatch这个action,让store通过reducers去做更新React Component 就是react的每个组件。
高阶函数:如果一个函数接受一个或多个函数作为参数或者返回一个函数就可称之为高阶函数。
高阶组件:如果一个函数 接受一个或多个组件作为参数并且返回一个组件 就可称之为 高阶组件。
react 中的高阶组件
React 中的高阶组件主要有两种形式:属性代理和反向继承。
属性代理 Proxy
props
state
ref
访问到组件实例WrappedComponent
反向继承
会发现其属性代理和反向继承的实现有些类似的地方,都是返回一个继承了某个父类的子类,只不过属性代理中继承的是 React.Component
,反向继承中继承的是传入的组件 WrappedComponent
。
反向继承可以用来做什么:
1.操作 state
高阶组件中可以读取、编辑和删除WrappedComponent
组件实例中的state
。甚至可以增加更多的state
项,但是非常不建议这么做因为这可能会导致state
难以维护及管理。
function withLogging(WrappedComponent) {
return class extends WrappedComponent {
render() {
return (
<div>;
<h2>;Debugger Component Logging...<h2>;
<p>;state:<p>;
<pre>;{JSON.stringify(this.state, null, 4)}<pre>;
<p>props:<p>;
<pre>{JSON.stringify(this.props, null, 4)}<pre>;
{super.render()}
<div>;
);
}
};
}
2.渲染劫持(Render Highjacking)
条件渲染通过 props.isLoading 这个条件来判断渲染哪个组件。
修改由 render() 输出的 React 元素树
1. JSX做表达式判断时候,需要强转为boolean类型
如果不使用
!!b
进行强转数据类型,会在页面里面输出0
。
render() {
const b = 0;
return <div>
{
!!b && <div>这是一段文本</div>
}
</div>
}
2. 尽量不要在 componentWillReviceProps
里使用 setState,如果一定要使用,那么需要判断结束条件,不然会出现无限重渲染,导致页面崩溃
3. 给组件添加ref时候,尽量不要使用匿名函数,因为当组件更新的时候,匿名函数会被当做新的prop处理,让ref属性接受到新函数的时候,react内部会先清空ref,也就是会以null为回调参数先执行一次ref这个props,然后在以该组件的实例执行一次ref,所以用匿名函数做ref的时候,有的时候去ref赋值后的属性会取到null
4. 遍历子节点的时候,不要用 index 作为组件的 key 进行传入
客户端路由实现的思想:
hashchange
事件,感知 hash 的变化history.go()
等 APIreact-router 实现的思想:
history
库来实现上述不同的客户端路由实现思想,并且能够保存历史记录等,磨平浏览器差异,上层无感知使用 react 经常会遇到几个组件需要共用状态数据的情况。这种情况下,我们最好将这部分共享的状态提升至他们最近的父组件当中进行管理。我们来看一下具体如何操作吧。
import React from 'react'
class Child_1 extends React.Component{
constructor(props){
super(props)
}
render(){
return (
<div>
<h1>{this.props.value+2}</h1>
</div>
)
}
}
class Child_2 extends React.Component{
constructor(props){
super(props)
}
render(){
return (
<div>
<h1>{this.props.value+1}</h1>
</div>
)
}
}
class Three extends React.Component {
constructor(props){
super(props)
this.state = {
txt:"牛逼"
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(e){
this.setState({
txt:e.target.value
})
}
render(){
return (
<div>
<input type="text" value={this.state.txt} onChange={this.handleChange}/>
<p>{this.state.txt}</p>
<Child_1 value={this.state.txt}/>
<Child_2 value={this.state.txt}/>
</div>
)
}
}
export default Three
this.state通常是用来初始化state的,this.setState是用来修改state值的。如果初始化了state之后再使用this.state,之前的state会被覆盖掉,如果使用this.setState,只会替换掉相应的state值。所以,如果想要修改state的值,就需要使用setState,而不能直接修改state,直接修改state之后页面是不会更新的。
相似性如下。
(1)都是用于创建UI的 JavaScript库。
(2)都是快速和轻量级的代码库(这里指 React核心库)。
(3)都有基于组件的架构。
(4)都使用虚拟DOM。
(5)都可以放在单独的HTML文件中,或者放在 Webpack设置的一个更复杂的模块中。
(6)都有独立但常用的路由器和状态管理库。
它们最大的区别在于 Vue. js通常使用HTML模板文件,而 React完全使用 JavaScript创建虚拟DOM。 Vue. js还具有对于“可变状态”的“ reactivity”的重新渲染的自动化检测系统。
key可以帮助 React跟踪循环创建列表中的虚拟DOM元素,了解哪些元素已更改、添加或删除。
每个绑定key的虚拟DOM元素,在兄弟元素之间都是独一无二的。在 React的和解过程中,比较新的虛拟DOM树与上一个虛拟DOM树之间的差异,并映射到页面中。key使 React处理列表中虛拟DOM时更加高效,因为 React可以使用虛拟DOM上的key属性,快速了解元素是新的、需要删除的,还是修改过的。如果没有key,Rεat就不知道列表中虚拟DOM元素与页面中的哪个元素相对应。所以在创建列表的时候,不要忽略key。
在getDerivedStateFromProps中进行处理。
这个生命周期函数是为了替代componentWillReceiveProps
存在的,所以在需要使用componentWillReceiveProps
时,就可以考虑使用getDerivedStateFromProps
来进行替代。
两者的参数是不相同的,而getDerivedStateFromProps
是一个静态函数,也就是这个函数不能通过this访问到class的属性,也并不推荐直接访问属性。而是应该通过参数提供的nextProps以及prevState来进行判断,根据新传入的props来映射到state。
需要注意的是,如果props传入的内容不需要影响到你的state,那么就需要返回一个null,这个返回值是必须的,所以尽量将其写到函数的末尾:
static getDerivedStateFromProps(nextProps, prevState) {
const {type} = nextProps;
// 当传入的type发生变化的时候,更新state
if (type !== prevState.type) {
return {
type,
};
}
// 否则,对于state不进行任何操作
return null;
}
shouldComponentUpdate
这个方法用来判断是否需要调用render方法重新描绘dom。因为dom的描绘非常消耗性能,如果我们能在shouldComponentUpdate方
法中能够写出更优化的dom diff
算法,可以极大的提高性能
父组件向子组件的子组件通信,向更深层子组件通信:
// context方式实现跨级组件通信
// Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据
const BatteryContext = createContext();
// 子组件的子组件
class GrandChild extends Component {
render(){
return (
<BatteryContext.Consumer>
{ color => <h1 style={{"color":color}}>我是红色的:{color}</h1>
} </BatteryContext.Consumer>
)
}
}
// 子组件
const Child = () =>{
return (
<GrandChild/>
)
}
// 父组件
class Parent extends Component {
state = {
color:"red"
}
render(){
const {color} = this.state
return (
<BatteryContext.Provider value={color}>
<Child></Child>
</BatteryContext.Provider>
)
}
}
class Input extends Component{
constructor(){
super();
this.state = {val:'100'}
}
handleChange = (e) =>{ //e是事件源
let val = e.target.value;
this.setState({val});
};
render(){
return (<div>
<input type="text" value={this.state.val} onChange={this.handleChange}/>
{this.state.val}
</div>)
}
}
class Sum extends Component{
constructor(){
super();
this.state = {result:''}
}
//通过ref设置的属性 可以通过this.refs获取到对应的dom元素
handleChange = () =>{
let result = this.refs.a.value + this.b.value;
this.setState({result});
};
render(){
return (
<div onChange={this.handleChange}>
<input type="number" ref="a"/>
{/*x代表的真实的dom,把元素挂载在了当前实例上*/}
<input type="number" ref={(x)=>{
this.b = x;
}}/>
{this.state.result}
</div>
)
}
}
简单地说,在 React中元素(虛拟DOM)描述了你在屏幕上看到的DOM元素。
换个说法就是,在 React中元素是页面中DOM元素的对象表示方式。在 React中组件是一个函数或一个类,它可以接受输入并返回一个元素。
注意:工作中,为了提高开发效率,通常使用JSX语法表示 React元素(虚拟DOM)。在编译的时候,把它转化成一个 React. createElement调用方法。
state 更新流程: 这个过程当中涉及的函数:
注意:此方法仅作为性能优化的方式而存在。不要企图依靠此方法来“阻止”渲染,因为这可能会产生 bug。应该考虑使用内置的 PureComponent 组件,而不是手动编写
shouldComponentUpdate()
props 更新流程: 相对于 state 更新,props 更新后唯一的区别是增加了对 componentWillReceiveProps 的调用。关于 componentWillReceiveProps,需要知道这些事情:
因为不能保证 props. children将是一个数组。
以下面的代码为例。
<Parent>
<h1>有课前端网</h1>
</Parent>
在父组件内部,如果尝试使用 props.children. map映射子对象,则会抛出错误,因为props. children是一个对象,而不是一个数组。
如果有多个子元素, React会使 props.children成为一个数组,如下所示。
<Parent>
<h1>有课前端网</h1>
<h2>前端技术学习平台</h2>
</Parent>;
//不建议使用如下方式,在这个案例中会抛出错误。
class Parent extends Component {
render() {
return <div> {this.props.children.map((obj) => obj)}</div>;
}
}
建议使用如下方式,避免在上一个案例中抛出错误。
class Parent extends Component {
render() {
return <div> {React.Children.map(this.props.children, (obj) => obj)}</div>;
}
}
Switch 通常被用来包裹 Route,用于渲染与路径匹配的第一个子 <Route>
或 <Redirect>
,它里面不能放其他元素。
假如不加 <Switch>
:
import { Route } from 'react-router-dom'
<Route path="/" component={Home}></Route>
<Route path="/login" component={Login}></Route>
Route 组件的 path 属性用于匹配路径,因为需要匹配 /
到 Home
,匹配 /login
到 Login
,所以需要两个 Route,但是不能这么写。这样写的话,当 URL 的 path 为 “/login” 时,<Route path="/" />
和<Route path="/login" />
都会被匹配,因此页面会展示 Home 和 Login 两个组件。这时就需要借助 <Switch>
来做到只显示一个匹配组件:
import { Switch, Route} from 'react-router-dom'
<Switch>
<Route path="/" component={Home}></Route>
<Route path="/login" component={Login}></Route>
</Switch>
此时,再访问 “/login” 路径时,却只显示了 Home 组件。这是就用到了exact属性,它的作用就是精确匹配路径,经常与<Switch>
联合使用。只有当 URL 和该 <Route>
的 path 属性完全一致的情况下才能匹配上:
import { Switch, Route} from 'react-router-dom'
<Switch>
<Route exact path="/" component={Home}></Route>
<Route exact path="/login" component={Login}></Route>
</Switch>
key
属性,方便比较。React
只会匹配相同 class
的 component
(这里面的class
指的是组件的名字)component
的 setState
方法的时候, React
将其标记为 - dirty
.到每一个事件循环结束, React
检查所有标记 dirty
的 component
重新绘制.shouldComponentUpdate
提高diff
的性能原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。