1. 创建方式
const Hello = (props) => { // 写法一
return <div>{props.message}</div>
}
// 写法二
const Hello = props => <div>{props.message}</div>
// 写法三
function Hello(props) {
return <div>{props.message}</div>
}
2. 函数组件代替类组件
面临的问题
- 函数组件没有state => React v16.8.0推出Hooks API,其中的一个API叫做useState可以解决问题
- 函数组件没有生命周期 => React v16.8.0推出Hooks API,其中的一个API叫做useEffect可以解决问题
我们对比一下两种组件实现 n + 1 的例子
类组件
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
n: 0
}
}
addN = () => {
this.setState({n: this.state.n + 1})
}
render() {
return (
<div className='App'>
<span>n:{this.state.n}</span>
<button onClick={this.addN}>n+1</button>
</div>
)
}
}
函数组件
const App = props => {
const [n,setN] = React.useState(0)
function addN(){
setN(n + 1)
}
return (
<div className='App'>
{n}
<button onClick={addN}>+1</button>
</div>
)
}
相比之下函数组件更为简洁一些
使用 useEffect 解决生命周期问题
- 模拟 componentDidMount 首次渲染
useEffect(() => { // 模拟componentDidMount 首次渲染
console.log('use effect')
},[]) // 空数组必须写
- 模拟 componentDidUpdate
const [n, setN] = React.useState(0)
useEffect(() => { // 模拟 componentDidUpdate
console.log('n 变化了')
},[n]) // 数组里面可以写多个参数表示监听多个变量
useEffect(() => { // 模拟 componentDidUpdate
console.log('任意属性变更了')
}) // 不写数组表示监听所有 useState 的变量
// 但是这样在第一次渲染时也会触发函数的执行 解决方法使用自定义Hook 见下一标题
- 模拟componentWillUnmount
useEffect(() => {
return () => {
console.log('Child 销毁了')
}
}) // 返回一个函数 在销毁时执行
- constructor
函数组件执行的时候,就相当于constructor
- shouldComponentUpdate
后面的 React.memo和useMemo可以解决
- render
函数组件的返回值就是render的返回值
// 模拟render里面写逻辑
const X = (props) => {
console.log('我是要写的逻辑')
return (
<div>逻辑模拟</div>
)
}
const App = props => {
let [childVisible, setChildVisible] = useState(true)
const changeVisible = () => {
setChildVisible(!childVisible)
}
return (
<div className='App'>
{childVisible ? <button onClick={changeVisible}>{childVisible}</button> :
<button onClick={changeVisible}>hide</button>}
{/*{childVisible ? <Child/> : null}*/}
<Child/>
<X/>
</div>
)
} // 一个函数便是一个组件
3. 自定义 Hook 之 useUpdate
解决上面 n 值初次渲染就执行的问题
const App = props => {
const [n, setN] = useState(0)
const onClick = () => {
setN(n + 1)
}
const [nUpdateCount, setNUpdateCount] = useState(0)
useEffect(() => { // 初次渲染就执行 + 1
setNUpdateCount(nUpdateCount + 1)
}, [n])
useEffect(() => { // 初次渲染就执行 判断是否大于1
if(nUpdateCount > 1){
console.log('n变了')
}
},[nUpdateCount])
return (
<div className='App'>
n值变成了:{n}
<button onClick={onClick}>n+1</button>
</div>
)
}
// 通过使用两次 useEffect 第一个触发第二个 useEffect 函数计数,大于0便是n值变化了
上面的代码很乱 改进一下
const useX = (fn, dep) => { // 这就是自定义 Hook 这就可以抽离成别的文件
const [count, setCount] = useState(0)
useEffect(() => {
setCount(x => x + 1)
}, [dep])
useEffect(() => {
if (count > 1) {
fn()
}
}, [count,fn])
}
const App = props => {
const [n, setN] = useState(0)
const onClick = () => {
setN(n + 1)
}
useX(() => {
console.log('n 变化了')
}, n)
return (
<div className='App'>
n值变成了:{n}
<button onClick={onClick}>n+1</button>
</div>
)
}