1. 创建方式
// 写法一const Hello = (props) => { return <div>{props.message}</div>} // 写法二const Hello = props => <div>{props.message}</div> // 写法三function Hello(props) { return <div>{props.message}</div>}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
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 } } addNum = () => { this.setState({n: this.state.n + 1}) } render() { return ( <div className='App'> <span>n:{this.state.n}</span> <button onClick={this.addNum}>n+1</button> </div> ) }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
函数组件
const App = props => { const [n,setN] = React.useState(0) function addNum(){ setN(n + 1) } return ( <div className='App'> {n} <button onClick={addNum}>+1</button> </div> )}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
相比之下函数组件更为简洁一些
使用 useEffect 解决生命周期问题
- 模拟 componentDidMount 首次渲染
useEffect(() => { // 模拟componentDidMount 首次渲染 console.log('use effect') },[]) // 空数组必须写
- 1
- 2
- 3
- 模拟 componentDidUpdate
const [n, setN] = React.useState(0)useEffect(() => { // 模拟 componentDidUpdate console.log('n 变化了') },[n]) // 数组里面可以写多个参数表示监听多个变量useEffect(() => { // 模拟 componentDidUpdate console.log('任意属性变更了') }) // 不写数组表示监听所有 useState 的变量// 但是这样在第一次渲染时也会触发函数的执行 解决方法使用自定义Hook 见下一标题
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 模拟componentWillUnmount
useEffect(() => { return () => { console.log('Child 销毁了') } }) // 返回一个函数 在销毁时执行
- 1
- 2
- 3
- 4
- 5
-
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> )} // 一个函数便是一个组件
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
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值变化了
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
上面的代码很乱 改进一下
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> )}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27