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> }