React入门
虚拟dom、jsx
- 从 JSX 到页面到底经过了什么样的过程:
- JSX 是 JavaScript 语言的一种语法扩展,长得像 HTML,但并不是 HTML。
- React.js 可以用 JSX 来描述你的组件长什么样的。
- JSX 在编译的时候会变成相应的 JavaScript 对象描述。
- react-dom 负责把这个用来描述 UI 信息的 JavaScript 对象变成 DOM 元素,并且渲染到页面上。
虚拟dom:
-
state异步合并:改变 state 数据时,由于 setState 是一个异步函数,当你一次调用多个 setState 时,React 并不会生成多次虚拟 DOM 而是将多次 setState 合并,然后生成一次虚拟 DOM 进行比对
-
js对比渲染:新的虚拟 DOM 与原来的虚拟 DOM 进行比对时,它会进行同层比较,即相同的节点层进行比较,如果不同则直接将原始虚拟 DOM 中该节点层及以下的节点全部删除,重新生成新的虚拟 DOM 节点,而不会继续向下比对
-
循环需要加key:你在 JSX 模板中遍历 state 中某个数据时,为什么不加 key 值浏览器会报错,这是因为你不再遍历的每条数据加上 key 值,更改 state 中那条数据的值,生成虚拟 DOM 后,React 就不知道原始遍历的数据和这次更新后遍历的数据一一对应的关系,就会再次重新渲染,而加上 key 值,它则能迅速比对出有差异的部分进行部分的更新。
-
为什么不建议用 index 作为 key 值:因为当你插入 / 删除中间的数据时,从改变的那个数据开始,后续每个数据的 index 值就会变,从而就导致了每个数据的 key 值相应变化了,这样依旧会引起大规模渲染,这就是其中的原因
// 普通的代码
<div class='box' id='content'>
<div class='title'>Hello</div>
<button>Click</button>
</div>
// 代码对应转化出来的js
// HTML 的信息和 JavaScript 所包含的结构和信息其实是一样的,我们可以用 JavaScript 对象来描述所有能用 HTML 表示的 UI 信息
{
tag: 'div',
attrs: { className: 'box', id: 'content'},
children: [
{
tag: 'div',
arrts: { className: 'title' },
children: ['Hello']
},
{
tag: 'button',
attrs: null,
children: ['Click']
}
]
}
// 编译后的代码
// React.createElement 会构建一个 JavaScript 对象来描述你 HTML 结构的信息,包括标签名、属性、还有子元素等。
class Header extends Component {
render () {
return (
React.createElement(
'div',
{ 'class': 'box', id: 'content' },
React.createElement(
'div',
{ 'class': 'title' },
'Hello'
),
React.createElement(
'button',
null,
'Click'
)
)
)
}
}
render(不要在render里setState)
- 一个组件类必须要实现一个 render 方法。
- 这个 render 方法必须要返回一个 JSX 元素。
- 必须要用一个外层的 JSX 元素把所有内容包裹起来。
// 错误
render () {
return (
<div>第一个</div>
<div>第二个</div>
)
}
// 正确
render () {
return (
<div>
<div>第一个</div>
<div>第二个</div>
</div>
)
}
// 定义常量
render () {
const className = 'header';
const isGoodWord = true;
return (
<div className={className}>
<h1>React 小书</h1>
{isGoodWord
? <strong> is good</strong>
: <span> is not good</span>
}
</div>
)
}
生命周期
class Header extends Component {
constructor () {
super()
// 最早渲染
console.log('construct')
}
// 组件挂载开始之前,也就是在组件调用 render 方法之前调用。
componentWillMount () {
console.log('component will mount')
}
// 组件挂载完成以后,也就是 DOM 元素已经插入页面后调用。
componentDidMount () {
console.log('component did mount')
}
render () {
console.log('render')
return (
<div>
<h1 className='title'>React 小书</h1>
</div>
)
}
}
// 控制台输出
construct
component will mount
render
component did mount
// 性能优化
// 你可以通过这个方法控制组件是否重新渲染。如果返回 false 组件就不会重新渲染。
shouldComponentUpdate(nextProps, nextState){
// 值没有发生过变化,不需要重新触发render
if(nextState.Number == this.state.Number){
return false
}
}
// 组件收到新的 props 之前调用
componentWillReceiveProps(nextProps){
}
componentWillUpdate():组件开始重新渲染之前调用。
componentDidUpdate():组件重新渲染并且把更改变更到真实的 DOM 以后调用。
// 组件对应的 DOM 元素从页面中删除之前调用。常用于离开页面清除定时器
componentWillUnmount(){
console.log('component will unmount')
}
dom操作之ref
以前我们通过手动 DOM 操作进行页面更新(例如借助 jQuery),而在 React.js 当中可以直接通过 setState 的方式重新渲染组件,渲染的时候可以把新的 props 传递给子组件,从而达到页面更新的效果。
// 我们给 input 元素加了一个 ref 属性,这个属性值是一个函数。
// 当 input元素在页面上挂载完成以后,React.js就会调用这个函数,
// 并且把这个挂载以后的 DOM 节点传给这个函数。
// 在函数中我们把这个 DOM元素设置为组件实例的一个属性,
// 这样以后我们就可以通过 this.input 获取到这个 DOM 元素
class AutoFocusInput extends Component {
componentDidMount () {
this.input.focus()
}
render () {
return (
<input ref={(input) => this.input = input} />
)
}
}
组件
- class组件
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component{
render(){
return(
//此处的this指的就是App组件,自定义在App上的属性就在this的props上
console.log(this),
<h1>Hello {this.props.name}React!</h1>
)
}
}
less语法
// 设置行内样式
// 之前html的写法
<h1 style='font-size: 12px; color: red;'>React.js 小书</h1>
// react的写法,参数驼峰
<h1 style={{fontSize: '12px', color: 'red'}}>React.js 小书</h1>
- 数据流(props、state)
- props
- state
使用方式:1 初始化state 2 setState修改state
- 注意:使用 setState() 方法修改状态,状态改变后,React会重新渲染组件
- 注意:不要直接修改state属性的值,这样不会重新渲染组件!!!
- 事件
父子组件传值
案例讲解
- 定义一个自定义组件
- 组件封装
- 父子组件传值