自定义React Hooks
1.为什么会出现hooks
这个东西捏 ❓
刚看hooks
就出现了这个问题 hooks
出现的意义在哪里呢
hooks
能解决什么问题
React
中组件有两种写法 一种类组件 一种函数组件
但是函数组件相对于类组件来说有一个小小滴缺点 就是没有state
😔
所以hooks
就应运而生勒😀
hooks
是一类特殊的函数 允许在React的函数式组件中"钩入"状态,生命周期等其他React
的特性
提供了一种无需类组件的方式,使得现在在函数式组件中可以使用像 this.state
,this.props
的概念勒🌵
2.那hooks
都这么厉害了 为什么还要有自定义的hooks
捏❔
正常的useState
接受两个参数
1
| const [state,setState]=useState('')
|
正常在类组件中setState
会支持两个参数: 一个是更新后的state
或者回调式更新的state
另一个参数是更新后的回调函数
tips
:什么是回调函数😓
回调 (callback) 是作为参数传递给另一个函数的函数 ,并在被调用函数执行完毕后被调用
个人的小理解: 回调函数就是先定义了functionA
然后再定义了functionB
但是在使用时候先用了functionB
并且把functionA
当成了参数给了functionB
useState
hook并不直接支持像类组件中的setState
方法那样可以接收第二个参数作为回调函数。useState
hook返回的更新函数只能用于更新状态,并且不会提供回调函数的选项
所以自定义hooks
就出现啦
3.来自定义useState
吧🍶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const useStatePro =(initState)=>{ const [state,setState]=useState(initState); const isUpdate=useRef() const setStatePro =(newState,cb)=>{ setState( prev=>{ isUpdate.current=cb return typeof newState='function' ? newState(prev):newState } ) } useEffect(()=>{ if(isUpdate.current) { return isUpdate.current() } }) return [state,useStatePro] }
|
这样就实现了useState
的功能 但是多了一个在状态更新后执行回调函数的功能
4.自定义一个更新函数useUpdate
如果正常使用hooks
想让组件重新渲染 一般是要更新state的
但是有的时候可能一个state掌握着好几个组件的生死大权😈
不能就为了一个小小的组件就让state作出无意义的更新
这时候可以想想能不能定义一个更新的hooks
来优雅一些实现组件的强制更新
1 2 3 4 5 6 7 8
| const Update=()=>{ const [,setFlag]=useState() const update=()=>{ setFlag(Date.now()) } return update }
|
发现这个函数返回了一个函数 这个函数就是用来强制更新的
咋使用他捏💅
1 2 3 4 5 6 7
| const Time=()=>{ const update=useUpdate(); return( {Date.now()} <div><button onCLick={update}>更新喽</button></div> ) }
|
5.自定义hooks实现redux
Redux
目前来说还是常用的管理状态的工具 但是Redux
需要遵守的规则和步骤有点小多😡
所以来制作一个属于自己的Redux
1.首先先把应用接口做好
在顶部引入Provider
组件为所有的儿孙组件提供所有数据源store
1 2 3 4 5 6 7 8 9 10 11
| import React from 'react'; import ReactDOM, {render} from 'react-dom'; import App from './components/App' import Provider from './store/provider'
render(( <Provider> <App/> </Provider> ), document.getElementById('app') )
|
2.然后就可以开始设计store
啦:happy:
首先就是数据项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const initState={ count:0; }
const reducer =(state,action)=>{ const{type,payload}=action switch(type){ case'ADD_COUNT':return{...state ,count:state.count+1} default : return state; } } const Context = React.createContext() const Provider = (props) => { const [state, dispatch] = useReducer(reducer, initState) return ( <Context.Provider value={{state, dispatch}}> {props.children} </Context.Provider> ) } export default { Context, Provider }
|
在这个数据项中可以看出 initState
reducer的定义和使用
redux`是一模一样的
重点看下面的创建的上下文 首先通过React.createContext()
创建一个空的上下文
然后定义Provider
这个组件 在内部用useReducer
把reducer
和初始化的initState
传入进去
返回的state
和dispatch
提供到Provider
作为数据源
数据项聚合一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const providers = [ Count.Provider, Todo.Provider ];
const ProvidersComposer = (props) => ( props.providers.reduceRight((children, Parent) => ( return Parent({children}) ), props.children) ) const Provider = (props) => { return ( <ProvidersComposer providers={providers}> {props.children} </ProvidersComposer> ) } export default Provider
|
最后出来的组件结构: Provider > Context.Provider > Context.Provider > App
我们通过ProviderComposer进行递归包裹,把每个Provider
进行一层一层的包裹 这里使用了parent({children})
替代了<Parent>{children}</Parent>
,这样的做法可以减少一层嵌套结构。
如何使用捏💩
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import React, { useContext, useEffect } from 'react';
import CountStore from '@/store/modules/count'
const App = (props) => { const {state, dispatch} = useContext(CountStore.Context) useEffect(() => { setInterval(() => { dispatch({ type: 'ADD_COUNT' }) }, 1000); }, []) return ( <div className='app'> {JSON.stringify(state)} </div> ) }
export default App
|
这样就实现啦一个小型redux
感觉比正常的redux
会好用一些捏