1.function组件
函数组件通常⽆无状态,仅关注内容展示,返回渲染结果即可。
从React16.8开始引⼊入了了hooks,函数组件也能够拥有状态。
⽤用function组件创建⼀一个Clock:
import React, { useState, useEffect } from 'react'
export default function ReactComponentFunction() {
const [date, setDate] = useState(new Date())
// useEffect在组件挂载之后执行
useEffect(() => {
console.log('useEffect')
const timer = setInterval(() => {
setDate(new Date())
}, 1000)
// return的函数会在函数组件将卸载时执行,相当于componentWillUnmoune
return () => clearInterval(timer)
// []中代表依赖项,当依赖项的发生变化是,useEffect重新执行,相当于componentDidUpdate
}, [])
return <div>function component: {date.toLocaleTimeString()}</div>
}
熟悉 React class 的⽣生命周期函数,可以把 useEffect Hook 看做 componentDidMount , componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
2.正确使用setState
setState(partialState, callback)
- partialState:object|function ⽤于产生与当前state合并的子集。
- callback:function state更更新之后被调⽤用
关于setState()应该了解的三件事:
1.不要直接修改State
// 错误示范:此代码不会重新渲染组件
this.state.comment = 'Hello';
// 正确使用
this.setState({comment: 'Hello'});
2.State的更新可能是异步的
出于性能考虑,React 可能会把多个 setState() 调用合并成⼀个调用。
如果想要获取到最新的状态值有以下方式:
- 在setState第二个参数—>回调函数中执行
- 使用定时器setTimeout中执行
- 在原生事件中修改状态
总结: setState只有在合成事件和生命周期函数中是异步的,在原生事件和setTimeout中都是同步的,这里的异步其实是批量更更新
3.State的更新会被合并
changeValue = v => {
this.setState({
counter: this.state.counter + v
});
};
setCounter = () => {
this.changeValue(1);
this.changeValue(2);
// 只会执行this.changeValue(2);
};
如果想要链式更新State:将setState第一个参数写成函数形式
changeValue = v => {
this.setState(state => ({ counter: state.counter + v }));
};
setCounter = () => {
this.changeValue(1);
this.changeValue(2);
};
3.组件复合
不具名用法:直接使用props.children
<div>
{showTop && <div>top</div>}
// 直接使用props.children
{this.props.children}
{showBottom && <div>bottom</div>}
</div>
具名用法:传个对象进去
<Layout title="home" showTop={true} showBottom={true}>
{
// 具名,传个对象
{
content: <h3>HomePage</h3>,
text: '这是个文本',
btnClick: () => console.log('btnClick'),
}
}
</Layout>
// 接收时使用
render() {
const { children, showTop, showBottom } = this.props
return (
<div>
{showTop && <div>top</div>}
{children.content}
{children.text}
<button onClick={children.btnClick}>button</button>
{showBottom && <div>bottom</div>}
</div>
)
}
4.Redux用法
1.创建store,src/store/index.js
import { createStore } from 'redux'
// 创建规则reducer,接受两个参数state、action,返回最新的state
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'ADD':
return (state += 1)
case 'MINUS':
return (state -= 1)
default:
return state
}
}
const store = createStore(counterReducer)
export default store
2.使用store
import React, { Component } from 'react'
import store from '../../store/index'
export default class ReduxPage extends Component {
componentDidMount() {
// 订阅store更新,强制更新
this.unsubscribe = store.subscribe(() => {
this.forceUpdate()
})
}
componentWillUnmount() {
// 组件销毁时,取消订阅
this.unsubscribe()
}
render() {
return (
<div>
<div>redux: {store.getState()}</div>
<button onClick={() => store.dispatch({ type: 'ADD' })}>ADD</button>
<button onClick={() => store.dispatch({ type: 'MINUS' })}>MINUS</button>
</div>
)
}
}
redux api:
- createStore(reducer) —— 创建store
- store.getState() —— 获取state值
- store.dispatch({type: 'XXX'}) —— 修改state状态
- store.subscribe(() => {}) —— 订阅state变化,并返回一个取消订阅方法
5.React-Redux用法
react-redux提供了了两个api
- Provider 为后代组件提供store
- connect 为组件提供数据和变更方法 —— connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
全局提供store,index.js
import { Provider } from 'react-redux'
import store from './store/index'
<Provider store={store}>
<App />
</Provider>
获取状态数据,ReactReduxPage.jsx
import React, { Component } from "react";
import { connect } from "react-redux";
class ReactReduxPage extends Component {
render() {
const { num, add, minus } = this.props;
return (
<div>
<h1>ReactReduxPage</h1>
<p>{num}</p>
<button onClick={add}>add</button>
<button onClick={minus}>minus</button>
</div>
); }
}
const mapStateToProps = state => {
return {
num: state,
};
};
const mapDispatchToProps = {
add: () => {
return { type: "add" };
},
minus: () => {
return { type: "minus" };
}
};
export default connect(
mapStateToProps, //状态映射 mapStateToProps
mapDispatchToProps, //派发事件映射
)(ReactReduxPage);
6.React-Redux Hook API
- userSelect() —— 获取store state
- useDispatch() —— 获取dispatch
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
export default function ReactReduxHook() {
const num = useSelector((state) => state)
const dispatch = useDispatch()
const add = () => dispatch({ type: 'ADD' })
const minus = () => dispatch({ type: 'MINUS' })
return (
<div>
<h3>ReactReduxHook</h3>
<p>{num}</p>
<button onClick={add}>add</button>
<button onClick={minus}>minus</button>
</div>
)
}
7.react-router
react-router中奉⾏⼀切皆组件的思想,路由器-Router、链接-Link、路由-Route、独占-Switch、重定向-Redirect都以组件形式存在
Route渲染内容的三种方式 Route渲染优先级:children>component>render。
这三种⽅方式互斥,你只能⽤用⼀一种。
children:func 有时候,不管location是否匹配,你都需要渲染⼀些内容,这时候你可以⽤用children。 除了不管location是否匹配都会被渲染之外,其它工作⽅方法与render完全⼀一样。
render:func 但是当你用render的时候,你调用的只是个函数。 只在当location匹配的时候渲染。
component: component
只在当location匹配的时候渲染。
{/* 添加Switch表示仅匹配⼀一个*/}
<Switch>
{/* 根路路由要添加exact,实现精确匹配 */}
<Route
exact
path="/"
component={HomePage}
/>
<Route path="/user" component={UserPage} />
<Route component={EmptyPage} />
</Switch>
8.纯组件PureComponent
React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component 并未实 现 shouldComponentUpdate() ,⽽而 React.PureComponent 中以浅层对⽐比 prop 和 state 的⽅方式来 实现了了该函数。
如果赋予 React 组件相同的 props 和 state, render() 函数会渲染相同的内容,那么在某些情况下使用 React.PureComponent 可提高性能。
9.react生命周期
挂载时:
- constructor
- static getDerivedStateFormProps(props, state) 返回null 或对象,返回对象则用于更新state
- render
- componentDidMount
更新时:
- static getDerivedStateFormProps(props, state)
- shouldComponentUpdate 返回true或false
- render
- getSnapshotBeforeUpdate 任何返回值将作为componentDidUpdate第三个参数
- componentDidUpdate(prevProps,prevState,snapshot)
卸载时:
- componentWillUnmount