一、React.js 简介
官方的介绍就不说了,只要明白React.js 不是一个框架,它只是一个库。它只提供 UI (view)层面的解决方案,所以从这种意义上来讲,它并不是一个完整的MVC,MVVM框架。在实际的项目当中,它并不能解决我们所有的问题,需要结合其它的库,例如 Redux、React-router 等来协助提供完整的解决方法。
二、React.js 安装
直接使用官网所推荐使用的工具来安装:
三、JSX 简介
所谓的 JSX 其实就是 JavaScript 对象,这种看起来“在 JavaScript 写的标签的”语法叫 JSX。编译的过程会把类似 HTML 的 JSX 结构转换成 JavaScript 的对象结构。每个 DOM 元素的结构都可以用 JavaScript 的对象来表示。你会发现一个 DOM 元素包含的信息其实只有三个:标签名,属性,子元素。可以用下图来理解:
主要记住几个点:
1.JSX 是 JavaScript 语言的一种语法扩展,长得像 HTML,但并不是 HTML。
2.React.js 可以用 JSX 来描述你的组件长什么样的。
3.JSX 在编译的时候会变成相应的 JavaScript 对象描述。
4.react-dom 负责把这个用来描述 UI 信息的 JavaScript 对象变成 DOM 元素,并且渲染到页面上。
四、组件的 render 方法
组件化可以帮助我们解决前端结构的复用性问题,整个页面可以由这样的不同的组件组合、嵌套构成。一个组件有自己的显示形态和行为,组件的显示形态和行为可以由数据状态(state)和配置参数(props)共同决定。数据状态和配置参数的改变都会影响到这个组件的显示形态。当数据变化的时候,组件的显示需要更新。所以如果组件化的模式能提供一种高效的方式自动化地帮助我们更新页面,那也就可以大大地降低我们代码的复杂度,带来更好的可维护性。
一个组件类必须要实现一个 render 方法,这个 render 方法必须要返回一个 JSX 元素。但这里要注意的是,必须要用一个外层的 JSX 元素把所有内容包裹起来。返回并列多个 JSX 元素是不合法的,下面是错误的做法:
必须要用一个外层元素把内容进行包裹:
- 表达式插入
在 JSX 当中你可以插入 JavaScript 的表达式,表达式返回的结果会相应地渲染到页面上。表达式用 {} 包裹。例如:12345678render () {const word = 'is good'return (<div><h1>React 小书 {word}</h1></div>)}
页面上就显示“React 小书 is good”。你也可以把它改成 {1 + 2},它就会显示 “React 小书 3”。你也可以把它写成一个函数表达式返回:
简而言之,{} 内可以放任何 JavaScript 的代码,包括变量、表达式计算、函数执行等等。 render 会把这些代码返回的内容如实地渲染到页面上,非常的灵活。表达式插入不仅仅可以用在标签内部,也可以用在标签的属性上,例如:
这样就可以为 div 标签添加一个叫 header 的类名。
注意,直接使用 class 在 React.js 的元素上添加类名如 <div class=“xxx”>
这种方式是不合法的。因为 class 是 JavaScript 的关键字,所以 React.js 中定义了一种新的方式:className 来帮助我们给元素添加类名。还有一个特例就是 for 属性,例如 <label for='male'>Male</label>
,因为 for 也是 JavaScript 的关键字,所以在 JSX 用 htmlFor 替代,即 <label htmlFor='male'>Male</label>
。
- 组件的组合、嵌套、组件树
自定义的组件都必须要用大写字母开头,普通的 HTML 标签都用小写字母开头。
五、事件监听
在 React.js 不需要手动调用浏览器原生的 addEventListener 进行事件监听。React.js 帮我们封装好了一系列的 on-的属性,当你需要为某个元素监听某个事件的时候,只需要简单地给它加上 on- 就可以了。而且你不需要考虑不同浏览器兼容性的问题,React.js都帮我们封装好这些细节了。
六、setState
setState 方法由父类 Component 所提供。当我们调用这个函数的时候,React.js 会更新组件的状态 state ,并且重新调用 render 方法,然后再把 render 方法所渲染的最新的内容显示到页面上。
注意,当我们要改变组件的状态的时候,不能直接用 this.state = xxx 这种方式来修改,如果这样做 React.js 就没办法知道你修改了组件的状态,它也就没有办法更新页面。所以,一定要使用 React.js 提供的 setState 方法,它接受一个对象或者函数作为参数。如下例子:
- setState 接受函数参数
这里还有要注意的是,当你调用 setState 的时候,React.js 并不会马上修改 state。而是把这个对象放到一个更新队列里面,稍后才会从队列当中把新的状态提取出来合并到 state 当中,然后再触发组件更新。这一点要好好注意。可以体会一下下面的代码:
你会发现两次打印的都是 false,即使我们中间已经 setState 过一次了。这并不是什么 bug,只是 React.js 的 setState 把你的传进来的状态缓存起来,稍后才会帮你更新到 state 上,所以你获取到的还是原来的 isLiked。所以如果你想在 setState 之后使用新的 state 来做后续运算就做不到了,例如:
上面的代码的运行结果并不能达到我们的预期,我们希望 count 运行结果是 3 ,可是最后得到的是 NaN。但是这种后续操作依赖前一个 setState 的结果的情况并不罕见。
这里就自然地引出了 setState 的第二种使用方式,可以接受一个函数作为参数。React.js 会把上一个 setState 的结果传入这个函数,你就可以使用该结果进行运算、操作,然后返回一个对象作为更新 state 的对象:
这样就可以达到上述的利用上一次 setState 结果进行运算的效果。
上面我们进行了三次 setState,但是实际上组件只会重新渲染一次,而不是三次;这是因为在 React.js 内部会把 JavaScript 事件循环中的消息队列的同一个消息中的 setState 都进行合并以后再重新渲染组件。
七、props
每个组件都可以接受一个 props参数,它是一个对象,包含了所有你对这个组件的配置。
- 默认配置 defaultProps
上面的组件默认配置我们是通过 || 操作符来实现。这种需要默认配置的情况在 React.js 中非常常见,所以 React.js 也提供了一种方式 defaultProps,可以方便的做到默认配置。如下所示:123456789101112131415161718192021222324252627class LikeButton extends Component {static defaultProps = {likedText: '取消',unlikedText: '点赞'}constructor () {super()this.state = { isLiked: false }}handleClickOnLikeButton () {this.setState({isLiked: !this.state.isLiked})}render () {return (<button onClick={this.handleClickOnLikeButton.bind(this)}>{this.state.isLiked? this.props.likedText: this.props.unlikedText} 👍</button>)}}
注意:props 一旦传入进来就不能改变,你不能改变一个组件被渲染的时候传进来的 props。但这并不意味着由 props 决定的显示形态不能被修改。组件的使用者可以主动地通过重新渲染的方式把新的 props 传入组件当中,这样这个组件中由 props 决定的显示形态也会得到相应的改变。
总结:
1.组件可以在内部通过 this.props 获取到配置参数,组件可以根据 props 的不同来确定自己的显示形态,达到可配置的效果。
2.可以通过给组件添加类属性 defaultProps 来配置默认参数。
3.props 一旦传入,你就不可以在组件内部对它进行修改。但是你可以通过父组件主动重新渲染的方式来传入新的 props,从而达到更新的效果。
八、state vs props
state 的主要作用是用于组件保存、控制、修改自己的可变状态。state 在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改。你可以认为 state 是一个局部的、只能被组件自身控制的数据源。state 中状态可以通过 this.setState方法进行更新,setState 会导致组件的重新渲染。
props 的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的 props,否则组件的 props 永远保持不变。
state 和 props 有着千丝万缕的关系。它们都可以决定组件的行为和显示形态。一个组件的 state 中的数据可以通过 props 传给子组件,一个组件可以使用外部传入的 props 来初始化自己的 state。但是它们的职责其实非常明晰分明:state 是让组件控制自己的状态,props 是让外部对组件自己进行配置。