1、自定义hook
当我们想在两个函数之间共享逻辑时, 我们会把它提取到第三个函数中,而组件和Hook都是函数,所以也同样适用这种方式
自定义hook是一个函数, 其名称是以use开头, 函数内部可以调用其他的hook
import React, {useEffect, useState} from 'react';
import ReactDom from 'react-dom' const useTimer = () => { //注意:这里的函数是需要以use开头 let [count, setCount] = useState(0) useEffect(() => { //相当于componentDidMount let timer = setInterval(() => { setCount(count => ++ count) }, 1000) return () => { //相当于componentWillUnmount clearInterval(timer) } }, []) return count }
const CounterOne = () => {
// let [count, setCount] = useState(0)
//
// useEffect(() => {
// let timer = setInterval(() => {
// setCount(count => ++ count)
// }, 1000)
// return () => {
// clearInterval(timer)
// }
// }, [])
let count = useTimer()
return <h2>CounterOne ---{count}</h2>
}
const CounterTwo = () => {
// let [count, setCount] = useState(0)
//
// useEffect(() => {
// let timer = setInterval(() => {
// setCount(count => ++ count)
// }, 1000)
// return () => {
// clearInterval(timer)
// }
// }, [])
let count = useTimer()
return <h3>CounterTwo ---{count}</h3>
}
const App = () => {
return <div>
<CounterOne/>
<CounterTwo/>
</div>
}
ReactDom.render(<App/>, window.root)
原本useEffect与useState是不能放在函数里,如果放在use开头的函数里,系统会认为是自定义的hook,这样就可以对对应的方法进行封装和使用
案例2: 对dispatch进行扩充,实现改变前与改变后值的打印
import React, {useEffect, useReducer} from 'react';
import ReactDom from 'react-dom'
const useLogger = () => {
const reducer = (state, config) => {
if(config.type === 'count') {
return {
...state,
count: state.count + config.step
}
} else if(config.type === 'name') {
return {
...state,
name: config.target
}
}
}
let [state, dispatch] = useReducer(reducer, {name: 'yfbill', count: 0})
const actions = (config) => { //对原有dispatch进行扩充 console.log('before', state) dispatch(config) } useEffect(() => { console.log('after', state) }) return [state, actions] //输出的扩充后的dispatch
}
const Item = () => {
let [state, actions] = useLogger()
return <div>
<h3>this is Item---name: {state.name} --- count: {state.count}</h3>
<button onClick={() => { actions({type: 'count', step: 1})}}>count++</button>
<button onClick={() => { actions({type: 'name', target: 'aaaa'})}}>changeName</button>
</div>
}
const App = () => {
return <div>
<h2>this is App</h2>
<Item/>
</div>
}
ReactDom.render(<App/>, window.root)
注意:以上这个嵌入式的写法可以用作数据的请求,方便封装操作
2、高阶组件的写法
import React from 'react'; import ReactDom from 'react-dom' const App = props => { console.log(props) return <div>this is App</div> } //扁平化的高阶组件(推荐使用) // const Wrap = (config = {}, Comp) => { // return props => { // return <Comp {...config} {...props}/> // } // } //第二种方式的高阶组件 const Wrap = (config = {}) => { return Comp => { return props => { return <Comp {...config} {...props}/> } } } // let Instance = Wrap({name: 'yfbill', age: 20}, App) let Instance = Wrap({name: 'yfbill', age: 20})(App) ReactDom.render(<Instance className="abc"/>, window.root)
通常来讲,高阶组件都是以with开头,通常来讲高阶组件不会直接渲染到return的内容里面,需要赋值后再进行处理
const App: React.FC = () => { let Comp = configTag({name: 'yf', age: 10}) return <StyleApp> <LayoutHeader/> <Content><Comp/></Content> </StyleApp> }
