新的react包包含了React.createElement,.createClass,.Component,.PropTypes,.children以及其他元素和组件类。这些都是你需要构建组件时助手。
而react-dom包包括ReactDOM.render,.unmountComponentAtNode和.findDOMNode。在 react-dom/server ,有ReactDOMServer.renderToString和.renderToStaticMarkup服务器端渲染支持。
总的来说,两者的区别就是:ReactDom是React的一部分。ReactDOM是React和DOM之间的粘合剂,一般用来定义单一的组件,或者结合ReactDOM.findDOMNode()来使用。更重要的是ReactDOM包已经允许开发者删除React包添加的非必要的代码,并将其移动到一个更合适的存储库。
方法一:外部定义函数
方法二:使用箭头函数添加
react中的组件在概念上来说是类似于JavaScript函数(即"props"),并返回用于页面展示的内容React元素
所谓的无状态组件,是指的其定义的值,无法被react监听到。
此处ele只是一个普通的变量,是没有状态的,区分组件的一个标准就是判断组件是否有状态的加入,状态即是数据,在Vue中状态管理器Vuex即被称为状态管理器,实际上就是对数据的一个存储器,React中的状态也等同于数据的 *** 纵,让数据驱动视图的响应。
在react中定义组件最简单的方式就是去使用js的函数。
当react为用户自定义组件时,它会将JSX所接收的属性以及子组件(children)转换为单个对象传递给组件,这个对象就被称之为“props”
基于类并且继承父类React组件,子类就能使用react所提供的特性。
construct中使用super()调用父类构造函数来初始化子类实例,super之前只是不能使用this,因为当前实例的父类构造函数没有执行,不具有父类的能力。
一、选取 DOM 元素在 jQuery 中,我们已经熟悉了使用 sizzle 选择器来完成 DOM 元素的选取。而在 React 中,我们可以使用 ref 来更有针对性的获取元素。
import React from 'react'class Demo extends React.Compoent {
getDomNode() {return this.refs.root// 获取 Dom Node}
render() {return (<div ref="root">just a
demo</div> ) }}
这是最简单的获取 node 的方式,如果有多层结构嵌套呢?没有关系。
import React from 'react'class Demo extends React.Compoent {
getRootNode() {return this.refs.root// 获取根节点 Dom Node}
getLeafNode() {return this.refs.leaf// 获取叶节点 Dom Node}
render() {return (<div ref="root">
<div ref="leaf">just a demo</div>
</div> ) }}
如果是组件和组件嵌套呢?也没关系,父组件仍然可以拿到子组件的根节点。
import React from 'react'import ReactDOM from 'react-dom'class Sub
extends React.Compoent {render() {return (
<div>a sub component</div> ) }}class Demo extends
React.Compoent {getDomNode() {return this.refs.root// 获取
Dom Node}getSubNode() {return
ReactDOM.findDOMNode(this.refs.sub)// 获取子组件根节点}render() {
return (<div ref="root"> <Sub
ref="sub" /> </div> ) }}
上面使用了比较易懂的 API 来解释 Ref 的用法,但里面包含了一些现在 React 不太推荐和即将废弃的方法,如果用 React 推荐的写法,我们可以这样写。
import React from 'react'import ReactDOM from 'react-dom'class Sub
extends React.Compoent {getDomNode() {return this.rootNode
}render() {return (<div ref={(c) =>
this.rootNode = c}>a sub component</div> ) }}class
Demo extends React.Compoent {getDomNode() {return
this.rootNode// 获取 Dom Node}getSubNode() {return
this.sub.getDomNode()// 获取子组件根节点}render() {return (
<div ref={(c) =>this.rootNode = c}>
<Sub ref={(c) =>this.sub = c} /> </div>
) }}
有人可能会问,那子组件怎么拿父组件的 Dom Node 呢,从 React
的单向数据流角度出发,遇到这种情况我们应该通过回调通知给父组件,再由父组件自行判断如何修改 Node,其实父组件拿子组件的 Node
情况也很少,大多数情况下我们是通过 props 传递变化给子组件,获取子组件
Node,更多的情况下是为了避开大量重新渲染去修改一些Node的属性(比如 scrollLeft)。
二、DOM *** 作
jQuery 中提供了丰富的 *** 作方法,但一个个 *** 作 DOM 元素有的时候真的很烦人并且容易出错。React 通过数据驱动的思想,通过改变 view 对应的数据,轻松实现 DOM 的增删 *** 作。
class Demo extends React.Compoent {constructor(props) {
super(props) this.state = {list: [1, 2, 3],
};this.addItemFromBottom = this.addItemFromBottom.bind(this)
this.addItemFromTop = this.addItemFromTop.bind(this)
this.deleteItem = this.deleteItem.bind(this) }
addItemFromBottom() {this.setState({list:
this.state.list.concat([4]),}) }addItemFromTop() {
this.setState({list: [0].concat(this.state.list),
}) }deleteItem() {const newList =
[...this.state.list] newList.pop() this.setState({
list: newList,}) }render() {return (
<div> {this.state.list.map((item) =>
<div>{item}</div>)}<button
onClick={this.addItemFromBottom}>尾部插入 Dom 元素</button>
<button onClick={this.addItemFromTop}>头部插入 Dom
元素</button> <button
onClick={this.deleteItem}>删除 Dom 元素</button>
</div> ) }} 三、事件的监听
React 通过根节点代理的方式,实现了一套很优雅的事件监听方案,在组件 unmount 时也不需要自己去处理内存回收相关的问题,非常的方便。
import React from 'react'class Demo extends React.Component {
constructor(props) {super(props) this.handleClick =
this.handleClick.bind(this) }handleClick() {
alert('我是d窗');}render() {return (<div
onClick={this.handleClick}>点击我d出d框</div> ) }}
这里有一个小细节就是
bind 的时机,bind 是为了保持相应函数的上下文,虽然也可以在 onClick 那里 bind,但这里选择在 constructor 里
bind 是因为前者会在每次 render 的时候都进行一次 bind,返回一个新函数,是比较消耗性能的做法。
但
React 的事件监听,毕竟只能监听至 root component,而我们在很多时候要去监听 window/document 上的事件,如果
resize、scroll,还有一些 React 处理不好的事件,比如
scroll,这些都需要我们自己来解决。事件监听为了屏蔽差异性需要做很多的工作,这里像大家推荐一个第三方库来完成这部分的工作,
add-dom-event-listener ,用法和原生的稍有区别,是因为这个库并不旨在做 polyfill,但用法还是很简单。
var addEventListener = require('add-dom-event-listener')var handler =
addEventListener(document.body, 'click', function(e){
console.log(e.target)// works for ie console.log(e.nativeEvent)//
native dom event})handler.remove()// detach event listener
另一个选择是 bean ,达到了 IE6+ 级别的兼容性。
四、事件的触发
和事件监听一样,无论是 Dom 事件还是自定义事件,都有很优秀的第三方库帮我们去处理,如果是 DOM 事件,推荐 bean ,如果是自定义事件的话,推荐 PubSubJS 。
五、document.ready
React
作为一个 view 层框架,通常情况下页面只有一个用于渲染 React 页面组件的根节点 div,因此
document.ready,只需把脚本放在这个 div 后面执行即可。而对于渲染完成后的回调,我们可以使用 React 提供的
componentDidMount 生命周期。
import React from 'react'class Demo
extends React.Component {constructor(props) {super(props)
}componentDidMount() {doSomethingAfterRender()//
在组件渲染完成后执行一些 *** 作,如远程获取数据,检测 DOM 变化等。}render() {return (
<div>just a demo</div> ) }} 六、attr 方法
jQuery 使用 attr 方法,获取 Dom 元素的属性。在 React 中也可以配合 Ref 直接读取 DOM 元素的属性。
import React from 'react'class Demo extends React.Component {
constructor(props) {super(props) }
componentDidMount() {this.rootNode.scrollLeft = 10//
渲染后将外层的滚动调至 10px}render() {return (<div
ref={(c) =>this.rootNode = c}
style={{ width: '100px', overflow: 'auto' }}>
<div style={{ width: '1000px' }}>just a demo</div>
</div> ) }}
但是,在大部分的情况下,我们完全不需要做,因为 React 的单向数据流和数据驱动渲染,我们可以不通过 DOM,轻松拿到和修改大部分我们需要的 DOM 属性。
import React from 'react'class Demo extends React.Component {
constructor(props) {super(props) this.state = {
link: '//www.taobao.com',} this.getLink =
this.getLink.bind(this) this.editLink =
this.editLink.bind(this) }getLink() {
alert(this.state.link) }editLink() {this.setState({
link: '//www.tmall.com',}) }render() {
return (<div> <a
href={this.state.link}>跳转链接</a> <button
onClick={this.getLink}>获取链接</button> <button
onClick={this.editLink}>修改链接</button> </div>
) }} 七、addClass/removeClass/toggleClass
在 jQuery 的时代,我们通常靠获取 Dom 元素后,再 addClass/removeClass 来改变外观。在 React 中通过数据驱动和第三库 classnames 修改样式从未如此轻松。
.fn-show {display: block}.fn-hide {display: none} import
React from 'react'import classnames from 'classnames'class Demo
extends React.Component {constructor(props) {super(props)
this.state = {show: true,}
this.changeShow = this.changeShow.bind(this) }changeShow() {
this.setState({show: !this.state.show, })
}render() {return (<div>
<a href="//www.taobao.com"
className={classnames({'fn-show':
this.state.show,'fn-hide': !this.state.show,
})}> 跳转链接
</a> <button
onClick={this.changeShow}>改变现实状态</button>
</div> ) }} 八、css
jQuery 的 css 方法用于设置 DOM 元素的 style 属性,在 React 中,我们可以直接设置 DOM 的 style 属性,如果想改变,和上面的 class 一样,用数据去驱动。
import React from 'react'class Demo extends React.Component {
constructor() {super(props) this.state = {
backgorund: 'white',} this.handleClick =
this.handleClick.bind(this) }handleClick() {
this.setState({background: 'black',}) }
render() {return (<div style={{
background: this.state.background,}}
> just a demo
<button>change Background Color</button>
</div> ) }} 九、数据存储
比起 jQuery,React 反而是更擅长管理数据,我们没有必要像 jQuery 时那样将数据放进 Dom 元素的属性里,而是利用 state 或者 内部变量(this.xxx) 来保存,在整个生命周期,我们都可以拿到这些数据进行比较和修改。
十、Ajax
Ajax 确实是在处理兼容性问题上一块令人比较头疼的地方,要兼容各种形式的 Xhr 不说,还有 jsonp 这个不属于 ajax
的功能也要同时考虑,好在已经有了很好的第三方库帮我们解决了这个问题,这里向大家推荐 natty-fetch ,一个兼容 IE8 的fetch
库,在 API 设计上向 fetch 标准靠近,而又保留了和 jQuery 类似的接口,熟悉 $.ajax 应该可以很快的上手。
十一、动画
React 在动画方面提供了一个插件 ReactCSSTransitionGroup ,和它的低级版本 ReactTransitionGroup ,注意这里的低级并不是退化版本,而是更加基础的暴露更多 API 的版本。
这个插件的灵感来自于 Angular 的 ng-animate,在设计思路上也基本保持一致。通过指定 Transition 的类名,比如
example ,在元素进场和退场的时候分别加上对应的类名,以实现 CSS3 动画。例如本例中,进场会添加 example-enter 和
example-enter-active 到对应的元素 ,而在退场 example-leave 和 example-leave-active
类名。当然你也可以指定不同的进场退场类名。而对应入场,React 也区分了两种类型,一种是 ReactCSSTransitionGroup
第一次渲染时(appear),而另一种是 ReactCSSTransitionGroup
已经渲染完成后,有新的元素插入进来(enter),这两种进场可以使用 prop
进行单独配置,禁止或者修改超时时长。具体的例子,在上面给出的链接中有详细的例子和说明,因此本文不再赘述。
但这个插件最多只提供了做动画的方案,如果我想在动画进行的过程中做一些其他事情呢?他就无能为力了,这时候就轮到
ReactTransitionGroup 出场了。ReactTransitionGroup 为他包裹的动画元素提供了六种新的生命周期:
componentWillAppear(callback) , componentDidAppear() ,
componentWillEnter(callback) , componentDidEnter() ,
componentWillLeave(callback) , componentDidLeave() 。这些 hook
可以帮助我们完成一些随着动画进行需要做的其他事。
但官方提供的插件有一个不足点,动画只是在进场和出场时进行的,如果我的组件不是
mount/unmount,而只是隐藏和显示怎么办?这里推荐一个第三方库: rc-animate ,从 API 设计上他基本上是延续了
ReactCSSTransitionGroup 的思路,但是通过引入 showProp 这一属性,使他可以 handle
组件显示隐藏这一情况下的出入场动画(只要将组件关于 show/hide 的属性传给 showProp 即可),同时这个库也提供自己的
hook,来实现 appear/enter/leave 时的回调。
如果你说我并不满足只是进场和出场动画,我要实现类似鼠标拖动时的实时动画,我需要的是一个 js 动画库,这里向大家推荐一个第三方库:
react-motion , react-motion
一个很大的特点是,有别以往使用贝塞尔曲线来定义动画节奏,引入了刚度和阻尼这些d簧系数来定义动画,按照作者的说法,与其纠结动画时长和很难掌握的贝塞尔表示法,通过不断调整刚度和阻尼来调试出最想要的d性效果才是最合理的。Readme
里提供了一系列的很炫的动画效果,比如这个 draggable list 。Motion 通过指定
defaultStyle、style,传回给子组件正在变化中的 style,从而实现 js 动画。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)