React 函数组件
如何创建函数组件
- 箭头函数形式
const Hello = (props) => { return <div>{props.message}</div> }
// 可以简写成
const Hello = props => <div>{props.message}</div>
- function 形式
function Hello(props) {
return <div>{props.message}</div>
}
函数组件 比 class组件 代码量少
看看这个例子,同样实现+1
class 组件
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
n: 1
}
}
click = () => {
this.setState(state => ({
n: state.n + 1
}))
}
render() {
return (
<div>
{this.state.n}
<button onClick={this.click}>+1</button>
</div>
)
}
}
函数组件
const App = props => {
const [n, setN] = useState(0)
const click = () => {
setN(n + 1)
}
return (
<div>
{n}
<button onClick={click}>+1</button>
</div>
)
}
看来函数组件真的有很大的优势
可以用函数组件代替 class 组件吗?
面临两个问题
- 函数组件没有 state
- 函数组件没有生命周期
没有 State 怎么办?
React v16.8.0 推出 Hooks API,其中的一个 API 叫做 useState 可解决问题
import React, { useState } from 'react';
function Example() {
// 声明一个叫 "count" 的 state 变量
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
没有生命周期怎么办?
React v16.8.0 推出 Hooks API,其中的一个 API 叫做 useEffect 可解决问题
- 模拟 componentDidMount
useEffect(()=> { console.log('第一次渲染') }, [])
// 第个参数是 [] 时,函数只在开始时执行一次
useEffect 的第二个参数是需要监听的state
属性,如果省略代表监听所有state
属性的变化,如果是空,则代表不监听任何state
属性
如果指定了需要监听的 state
对象,那么就只会监听这一个 state
属性。其他属性的变化,不会触发函数的执行
- 模拟 componentDidUpdate
useEffect(() => { console.log('任意属性变更') })
useEffect(()=> { console.log('n变了') }, [n])
// 不传入第二个参数时,监听全部属性
// 传入 [n] 时,只监听 n
但是这样并不能真正模拟 componentDidUpdate,因为它不会在第一次渲染时执行,而上面的代码无法做到这一点
所以为了修改这个问题,我们需要增加一些代码
const [nUpdateCount, setNUpdateCount] = useState(0)
useEffect(() => {
setNUpdateCount(nUpdateCount => nUpdateCount + 1)
}, [n])
useEffect(() => {
if (nUpdateCount > 1) {
console.log('更新了一次')
}
}, [nUpdateCount])
我们可以通过 nUpdateCount
来解决这个问题,nUpdateCount
检测到 n
的第一次变化,重 0
变为 1
,而 useEffect
中判断 nUpdateCount
大于 1
时,才开始执行
但是这样的代码似乎还是有点繁琐,还可以继续优化
写成一个 useUpdate
函数,fn
是更新时执行的函数,dey
是监听对象,这个函数可以从组件中提取处理,使用时直接应用
const useUpdate = (fn, dey) => {
const [count, setCount] = useState(0)
useEffect(() => {
setCount(count => count + 1)
}, [dey])
useEffect(() => {
if (count > 1) {fn()}
}, [count, fn])
}
组件中直接调用 useUpdate
useUpdate(() => {console.log('更新了一次')}, n)
- 模拟 componmentWillUnmount
useEffect(() => {
console.log('数据更新了')
return () => {
console.log("我要被销毁了")
}
})
useEffect可以再返回一个函数,他会在组件消失时调用,而console.log(
'数据更新了')
则会在组件发生变化重渲染时调用
- 模拟 shouldComponentUpdate
const MyComponent = React.memo(
_MyComponent,
(prevProps, nextProps) => nextProps.count !== prevProps.count
)
React.memo 包裹一个组件来对它的 props 进行浅比较,但这不是一个 hooks,因为它的写法和 hooks 不同,其实React.memo 等效于 PureComponent,但它只比较 props。