1、Props - 外部数据
- 传入 props 给 B 组件
class Parent extends React.Component{
constructor(props){
super(props)
this.state = {name:'wbh'}
}
onClick = ()={}
render(){
return <B name = {this.state.name}
onClick = {this.onClick}>hi</B>
}
}
-
- 外部数据被包装成一个对象
- {name:'wbh',onClick:...,children:'hi'}
- 此处的 onClick 是一个回调
-
读取 props
class Parent extends React.Component{
constructor(props){
super(props)
}
render(){
return <div onClick = {this.props.onClick}>
{this.props.name}
<div>{this.props.children}</div>
</div>
}
}
//this.props.children 就是 'hi'
//通过 this.props.xxx 来读取
- 不准写 props
2、props 相关钩子
componmentWillReceiveProps钩子- 当组件接受新的 props 时,会触发此钩子
- 钩子也就是特殊函数
- 但是这个钩子已经被弃用了
- 更名为
UNSAFE_componmentWillReceiveProps
- 其他被弃用的钩子:
componentWillMount()componentWillUpdate()
3、Props 的作用
-
接受外部数据
- 只能读不能写
- 外部数据由父组件传递
-
接受外部函数
- 在恰当的时机,调用该函数
- 该函数一般是父组件的函数
-
示例:
class App extends React.Component{
constructor(props) {
super(props);
this.state = {
x:1
}
}
onClick = () => this.setState({x:this.state.x + 1 })
render() {
return (
<div>
<B name = {this.state.x} onClick = {this.onClick}/>
</div>
}
class B extends React.Component{
constructor(props) {super(props);}
render() {
return (
<div>
{this.props.name}
<button onClick={this.props.onClick}>+1</button>
</div>
);
}
}
4、读写 state
-
读用
this.state -
写用
this.setState(newState, fn)- 示例:
onClick = ()=>{ this.setState({x: this.state.x + 1}) } - 注意 setState 不会立刻改变 this.state,会在当前代码运行完后,再去更新 this.state,从而触发 UI 更新
- this.setState((state,props)=>newState,fn)(更推荐)
- 示例:
onClick2 = ()=>{ this.setState((state,props) => ({x: state.x + 1})) }
- 示例:
-
写时会 shallow merge: setState 会自动将新 state 与旧 state 进行一级合并
5、生命周期
- 类比于
let div = document.createElement('div')
//这是 div 的 create/construct 过程
div.textContent = 'hi'
//这是初始化 state
document.body.appendChild(div)
//这是 div 的 mount 过程
div.textContent = 'hi2'
//这是 div 的 update 过程
div.remove()
//这是 div 的 unmount 过程
- 函数列表
- constructor() - 在这里初始化 state
- shouldComponentUpdaet() - return false 组织更新
- render() - 创建虚拟 DOM
- componentDidMount() - 组件已经出现在页面
- componentDidUpdate() - 组件已经更新
- componentWillUnmount() - 组件将要卸载、死亡
5、constructor
- 用途
- 初始化 props
- 初始化 state,但此时不能调用 setState 来设置
- 可不写
- 用来写 bind this
constructor(){
...
this.onClick = this.onClick.bind(this)
}
//这种写法等价于
onClick = () => { }
constructor(){...}
6、shouldComponentUpdate
- 用途
- 返回 true 表示不阻止 UI 更新
- 返回 false 表示阻止 UI 更新
- 示例:
class App extends React.PureComponent{
constructor() {
super();
this.state = {
n:1
}
}
onClick = () => {
this.setState((state) => ({
n: state.n + 1
}));
this.setState((state) => ({
n: state.n - 1
}))
}
render() {
console.log('render了1次')
return (
<div>
App
<div>
{this.state.n}
<button onClick={this.onClick}>+1</button>
</div>
</div>
)
}
}
-
面试常问:shouldComponentUpdate 有什么用
-
答:它允许我们手动判断是否要进行组件更新,我们可以根据应用场景灵活地设置返回值,以避免不必要的更新
-
React.PureComponent 是 React 内置的可代替 shouldComponentUpdate 的一个方法,用于代替 React.Copmonent
- PureComponent 会在 render 之前对比新 state 和旧 state 的每一个 key,以及新 props 和旧 props 的每一个 key。
- 如果所有 key 的值全都一样,就不会 render;如果有任何一个 key 的值不同,就会 render。
- 示例:
class App extends React.PureComponent{
...
}
7、render
- 用途
- 展示视图
- return ( )
- 只能有一个根元素(div)
- 如果有两个根元素,就要用<React.Fragment> 包起
- <React.Fragment /> 可以缩写成 <></>
- 技巧
- render 里面可以写 if...else
- 示例;
render(){
let message
if(this.state.n % 2 === 0){
message = <div>偶数</div>
}else{
message = <div>奇数</div>
}
return (
<>
{message}
<button>+1</button>
</>
)
}
-
- render 里面可以写 ?: 表达式
- 示例:
render(){
return (
<div>
{this.state.n % 2 === 0?
<div>偶数</div>:
<div>奇数</div>
}
//只显示偶数的时候
{this.state.n % 2 === 0 && <div>偶数</div>}
</div>
)
}
-
- render 里面不能直接写 for 循环,for 循环无法 return,需要使用数组
- 示例:
render(){
let result;
for(let i=0; i<this.state.array.length;i++){
result.push(this.state.array[i])
}
return result
}
-
- render 里面可以写 array.map (循环)
- 注意:所有循环都要加上 key
- 示例:
render(){
return this.state.array.map(n => <div key={n}>{n}</div>)
}
8、componentDidMount
-
用途
- 在元素插入页面后执行代码,这些代码依赖 DOM
- 比如想要获取 div 的高度,就最好在这里写
- 此处可以发起加载数据的 AJAX 请求(官方推荐)
- 首次渲染会执行此钩子
-
此钩子不接受参数
- 示例1:
constructor(){
...
this.state = {
width: undefined
}
}
componentDidMount() {
const xxx = document.querySelector('#xxx')
const width = xxx.getBoundingClientRect().width
this.setState(state => ({
width
}))
}
render() {
return (
<div id="xxx">
{this.state.width}px
</div>
)
}
-
- 示例2:
//不使用 id 来获取元素,使用 ref
divRef = undifined
constructor(){
...
this.divRef = React.createRef()
}
componentDidMount() {
const div = this.divRef.current
const width = div.getBoundingClientRect().width
this.setState(state => ({
width
}))
}
render() {
return (
<div ref={this.divRef}>
{this.state.width}px
</div>
)
}
9、componentDidUpdate
- 用途
- 在视图更新后执行代码
- 此处也可以发起 AJAX 请求,用于更新数据
- 首次渲染不会执行此钩子
- 在此处 setState 可能会引起无限循环,除非放在 if 中
- 若 shouldComponentUpdate 返回 false,则不触发这个钩子
- 参数:prevProps, prevState
10、componentWillUnmount
- 用途
- 组件将要被移除页面然后被销毁时执行代码
- unmount 过的组件不会再次 mount
- 举例
- 比如在 componentDidMount 里面监听了 window.scroll、Timer、AJAX 请求等,那么就要在 componmentWillUnmount 中取消请求
- 也可以不写
11、钩子执行顺序
