由于React的简陋 【什么都没有】的API的设计,在React组件使用过渡动画十分困难,当然可以用 react-transition-group ,不过不好用啊!
相比Vue官方的过渡组件transition 组件就十分强大,很贴心 ,确切的说真香!
鉴于React什么都没有,什么都需要你自己搞 的情况下,在这里就研究下React的过渡组件的实现…
my-React-Transition-Group
classnames 源码
1 | (function () { |
React 顶层 API
React 相关方法(API)介绍-元素与组件操作
React 新特性讲解及实例Context,ContextType,lazy,Suspense,错误边界(Error boundaries),memo
react中实用的一些API
React.createClass:
创建一个ReactClass(组件类),参数是一个对象且必须带有 render 属性方法,该方法必须返回一个封闭的容器(容器内可以有其它不限结构的容器)或 null/false(表示啥都不渲染)
React.createElement
React.createElement:第一个参数是DOM,第二个是属性,第三个是值
创建一个指定类型的React元素,注意第三个参数children可以是任意个React元素:1
2
3
4
5
6React.createElement( 'p', null,
React.createElement('span', null, 'Hello,'),
React.createElement('span', null, 'world,'),
React.createElement( Component, {a : 1})
)
React.createElement(type, props, children)如:React.createElement('span', null, 'Hello,')
React.cloneElement:
克隆并返回一个新的 ReactElement (内部子元素也会跟着克隆),新返回的元素会保留有旧元素的 props、ref、key,也会集成新的 props(只要在第二个参数中有定义)
var newSpan = React.cloneElement(span, {b:’2’}
要注意的是,createElement 的第一个参数必须是字符串或 ReactClass,而在 cloneElement 里第一个参数应该是 ReactElement
React.createFactory:
返回一个某种类型的ReactElement工厂函数,可以利用返回的函数来创建一个ReactElement(配置 props 和 children)1
2
3
4var p = React.createFactory(Component),
ReactElementP = p({a:1}),
div = React.createFactory('div'),
ReactElementDiv = div(null, ReactElementP);
React.Children:
React.Children.map(object children, function fn [, object context])
遍历子元素,映射为一个新的子元素集合(跟 ES5 的 Array.map 差不多)React.Children.forEach(object children, function fn [, object context])
遍历子元素,对每一个子元素执行回调,但不像上述的 map 那样最终返回一个新的集合(跟 ES5 的 Array.forEach 差不多)React.Children.count(object children)
返回子元素的总数React.Children.only(object children)
返回仅有的一个子元素,否则(没有子元素或超过一个子元素)报错且不渲染任何东西:
5.React.initializeTouchEvents:
开启或关闭 React 的触摸事件机制,传入参数 true 使 React 能处理移动设备的触摸( touch )事件
React.DOM.tag:
常规是用于在非 JSX 下来创建 ReactElement,tag 表示相应的DOM类型(比如“div”、“p”)。另外首个参数可以定制相关的 DOM 属性(比如“name”),第二个参数表示 DOM 内的内容1
2
3
4
5
6
7var div = React.DOM.div({name : 'div1'},
'HELLO ',
React.DOM.span(null, <em>WORLD</em>)
);
React.render(
div, document.body
)
生成结果:1
2
3
4
5
6<div name="div1" data-reactid=".0">
<span data-reactid=".0.0">HELLO</span>
<span data-reactid=".0.1">
<em data-reactid=".0.1.0">WORLD</em>
</span>
</div>
React.isValidElement:
判断参数是否一个合法的 ReactElement,并返回 Boolean 值1
2
3
4
5
6
7
8
9
10var Component = React.createClass({
render: function() {
return this.props.a==1 ? <p>123</p> : null
}
});
var com = <Component/>,
com2 = '<Component/>';
console.log(React.isValidElement(com)); //true
console.log(React.isValidElement(com2)); //false
React.renderToStaticMarkup:
类似 React.renderToString ,但只生成纯粹的HTML标记字符串,不会包含类似 data-reactid 之类的React属性,从而节省字节数1
2
3
4
5
6
7
8
9var Component = React.createClass({
render: function() {
return this.props.a==1 ? <p>123</p> : null
}
});
var com = <Component a="1" />,
comHTML = React.renderToStaticMarkup(com);
console.log(comHTML); //输出“<p>123</p>”
React.renderToString:
React为服务端提供的一个方法,可以直接输出 ReactElement 为 HTML 字符串,将这些标记发送(比如 res.write(HTMLString))给客户端,可以获得更快的页面加载速度,并且有利于搜索引擎抓取页面,方便做 SEO(主要是百度不争气,谷歌早可以从内存中去抓最终生成的HTML内容了)1
2
3
4
5
6
7
8var Component = React.createClass({
render: function() {
return this.props.a==1 ? <p>123</p> : null
}
});
var com = <Component a="1" />,
comHTML = React.renderToString(com);
console.log(comHTML); // 输出“<p data-reactid=".0" data-react-checksum="-2122315716">123</p>”
Transition.js
1 | import React from 'react' |
TransitionGroup.js
1 | import React, { Children, cloneElement, isValidElement } from "react" |
transition.css
1 |
|
组件中的使用
1 | import React, { Component } from 'react'; |
插件中实用
1 | import React from "react"; |
React中的Component 和 PureComponent
React.Component
和React.PureComponent
很相似,两则的区别在于,PureComponent
类帮我们以浅比较的方式对比props
和state
,实现了shouldComponentUpdate()
函数,在某些情况下,使用PureComponent
可以减少render
函数的执行,提升性能。
PureComponent能够提升性能
当Index组件继承Component
类
初次渲染时控制台会依次打印”
constructor
“、”render
“;当第一次点击按钮更新
state
时,控制台会依次打印”render
“、”componentDidUpdate
“;后续每次触发点击事件,尽管flag的值没有变化,控制台还是会依次打印”
render
“、”componentDidUpdate
“,说明组件依然调用render()
、componentDidUpdate()
函数,显然这是多余的,通常我们会手动重新实现shouldComponentUpdate(nextProps, nextState)
函数判断state
、props
的状态再来决定是否需要重新渲染
1 | import React from 'react'; |
当Index组件继承PureComponent
类
初次渲染和第一次点击按钮更新
state
时控制台输出同上面继承Component
一样没有变化后续每次触发点击事件,控制台无输出, 省去执行
render
函数生成虚拟DOM,进行DIFF算法比较等后续操作
1 | if (this._compositeType === CompositeTypes.PureClass) { |
PureComponent
默认实现的shouldComponentUpdate()
方法使用的是浅比较: 即值的比较或引用的比较, 不会进行深层次的对比,所以当props
或state
的值是引用类型时,即使对象的值改变了,但是对象的引用没变
1 | import React from 'react'; |
- 初次渲染时控制台会打印
render (5) [1, 2, 3, 4, 5]
- 当点击pop按钮时控制台会依次打印
changeArr (4) [1, 2, 3, 4]
,changeArr (4) [1, 2, 3]`
……但是
render函数不执行, 因为
PureComponent实现的
shouldComponentUpdate()认为值的引用没有变,故不执行后续的操作,只有在引用改变的情况下函数才会返回
true`
PureComponent也会影响子组件
下面例子中的render
函数只会在刚创建的时候执行一次, 后续的点击按钮操作,由于PureComponent
中的ShouldComponentUpdate()
执行浅比较(对象值的引用没变),不会触发render
函数的执行,其子组件也不会更新。
1 | import React from 'react'; |
1 |
|
总结
PureComponent
已经用浅层对比props
、state
的方式替我们实现了shouldComponentUpdate()
, 不仅能影响自身,还会影响其子组件;PureComponent
某些情况下(props
或state
的值不经常变动, 因为浅比较也会耗时)可以提升性能;- 继承自
Component
中的组件shouldComponentUpdate()
默认情况下总是返回true;