ReactJs小书笔记(二)
ReactJs小书官方文档:传送门
17 前端应用状态管理——状态提升
- 概念:当平级的组件之间的需要进行数据传递的时候,需要将组件之间的共享的状态交给组件附近最近的父节点保管,然后通过
props
把状态传递给子组件,实现组件之间的数据共享; - 总结:当某个状态被多个组件依赖或者影响的时候,就把该状态提升到这些组件的最近公共父组件中去管理,用 props 传递数据或者函数来管理这种依赖或着影响的行为;
- 问题:一旦发生状态提升,就需要修改原来保存这个状态的组件的代码,也要把整个数据传递路径经过的组件都修改一遍,好让数据能够一层层地传递下去;这样对代码的组织管理维护带来很大的问题。
18 挂载阶段的组件生命周期(1)
- 组件初始化阶段
- constructor():(构造器)初始化组件;
- componentWillMount():组件挂载开始之前,也就是在组件调用 render 方法之前调用;
- render(): 将构造好的 DOM 元素挂载到页面;
- componentDidMount():组件挂载完成以后,也就是 DOM 元素已经插入页面后调用;
- 组件的删除阶段
- 即将从页面中删除
- componentWillUnmount():组件对应的 DOM 元素从页面中删除之前调用;
- 从页面中删除
19 挂载阶段的组件生命周期(2)
利用生命周期函数实现一个时钟的应用:
import React, { Component } from 'react';
class Clock extends Component {
constructor () {
super()
this.state = {
date: new Date()
}
}
componentWillMount () {
this.timer = setInterval(() => {
this.setState({ date: new Date() })
}, 1000)
}
render () {
return (
<div>
<p>现在的时间是:</p>
<h3>
{this.state.date.toLocaleTimeString()}
</h3>
</div>
)
}
}
class App extends Component {
constructor () {
super()
this.state = { isShowClock: true }
}
handleShowOrHide () {
this.setState({
isShowClock: !this.state.isShowClock
})
}
render () {
return (
<div>
{this.state.isShowClock ? <Clock /> : null }
<button onClick={this.handleShowOrHide.bind(this)}>
显示或隐藏时钟
</button>
</div>
)
}
componentWillUnmount () {
clearInterval(this.timer)
}
}
export default App;
20 更新阶段的组件生命周期
- shouldComponentUpdate(nextProps, nextState):你可以通过这个方法控制组件是否重新渲染;如果返回
false
组件就不会重新渲染。这个生命周期在 React.js 性能优化上非常有用; - componentWillReceiveProps(nextProps):组件从父组件接收到新的 props 之前调用;
- componentWillUpdate():组件开始重新渲染之前调用;
- render() :将构造好的 DOM 元素挂载到页面;
- componentDidUpdate():组件重新渲染并且把更改变更到真实的 DOM 以后调用;
21 ref 和 React.js中的DOM操作
-
React.js
中基本不会和DOM直接打交道;React.js
提供了一系列的on*
方法帮助我们进行事件监听,所以 React.js 当中不需要直接调用addEventListener
的 DOM API;并且React.js
重新渲染的机制帮助我们免除了绝大部分的 DOM 更新操作; -
React.js
当中提供了ref
属性来帮助我们获取已经挂载的元素的DOM
节点,可以给某个 JSX 元素加上ref
属性,如 进入页面实现自动focus
到输入框:
class AutoFocusInput extends Component {
componentDidMount () {
this.input.focus()
}
render () {
return (
<input ref={(input) => this.input = input} />
)
}
}
ReactDOM.render(
<AutoFocusInput />,
document.getElementById('root')
)
- 组件标签也可以使用
ref
属性,获取该组件的DOM节点;
注意: ReactJs
中能不用 ref
就不用;特别是要避免用 ref
来做 React.js 本来就可以帮助你做到的页面自动更新的操作和事件监听,多余的 DOM 操作其实是代码里面的“噪音”,不利于我们理解和维护。
22 props.children 和容器类组件
- 容器类的组件中可以填充任意的内容,其定义了一种外层的结构,如下:
import React, { Component } from 'react';
class Card extend Component {
constructor () {
super()
this.state= {}
}
render(
<div className='card'>
<div className='card-content'>
{this.props.content}
</div>
</div>
)
}
ReactDOM.render(
{/*通过给 Card 组件传入一个 content 属性,这个属性可以传入任意的 JSX 结构。然后在 Card 内部会通过 {this.props.content} 把内容渲染到页面上*/}
<Card content={
<div>
<h2>React.js 小书</h2>
<div>开源、免费、专业、简单</div>
订阅:<input />
</div>
} />,
document.getElementById('root')
)
- 使用
props.children
,能够使得组件获取所有嵌套在组件中的 JSX 结构,如下:
import React, { Component } from 'react';
class Card extends Component {
render () {
return (
<div className='card'>
<div className='card-content'>
{this.props.children}
</div>
</div>
)
}
}
ReactDOM.render(
<Card>
<h2>React.js 小书</h2>
<div>开源、免费、专业、简单</div>
订阅:<input />
</Card>,
document.getElementById('root')
)
- 将
props.children
值打印出来,可以知道其本质是一个数组,因而甚至可以在组件内部把数组中的JSX
元素安置在不同的地方:
class Layout extends Component {
render () {
return (
<div className='two-cols-layout'>
<div className='sidebar'>
{this.props.children[0]}
</div>
<div className='main'>
{this.props.children[1]}
</div>
</div>
)
}
}
23 dangerouslySetHTML 和 style 属性
23.1 dangerouslySetHTML 属性
- 出于安全考虑的原因(XSS 攻击),在
React.js
当中所有的表达式插入的内容都会被自动转义,就相当于 jQuery 里面的text(…)
函数一样,任何的 HTML 格式都会被转义掉,而React.js
提供了一个属性dangerouslySetInnerHTML
,可以让我们设置动态设置元素的innerHTML
:
class Editor extends Component {
constructor() {
super()
this.state = {
content: '<h1>React.js 小书</h1>'
}
}
// content中的内容会完全展示,其中 h1 标签被转义了,显示为字符串
render () {
return (
<div className='editor-wrapper'>
{this.state.content}
</div>
)
}
// 使用 `dangerouslySetInnerHTML` 属性能够设置动态设置元素的 `innerHTML`
render () {
return (
<div
className='editor-wrapper'
dangerouslySetInnerHTML={{__html: this.state.content}} />
)
}
}
23.2 style 属性
在 React.js
中使用 style
属性时,需要把 CSS 属性变成一个对象再传给元素:
<h1 style={{fontSize: '12px', color: 'red'}}>React.js 小书</h1>
其中 style
接受一个对象,这个对象里面是这个元素的 CSS 属性键值对,原来 CSS 属性中带 -
的元素都必须要去掉 -
换成驼峰命名
;
24 PropTypes 和组件参数验证
- 原由:JavaScript 的灵活性体现在弱类型、高阶函数等语言特性上,然而语言的弱类型很容易出 bug,所以在
React.js
中给组件的配置参数加上类型验证; - 安装使用
React
提供的第三方库prop-types
进行类型验证:npm install --save prop-types
;
import React, { Component } from 'react'
import PropTypes from 'prop-types'
class Comment extends Component {
static propTypes = {
comment: PropTypes.object
}
render () {
const { comment } = this.props
return (
<div className='comment'>
<div className='comment-user'>
<span>{comment.username} </span>:
</div>
<p>{comment.content}</p>
</div>
)
}
-
prop-types
类型验证参数:
PropTypes.array
PropTypes.bool
PropTypes.func
PropTypes.number
PropTypes.object
PropTypes.string
PropTypes.node
PropTypes.element
-
prop-types
中通过isRequired
关键字来强制组件某个参数必须传入:
...
static propTypes = {
comment: PropTypes.object.isRequired
}
...