Hooks是React16.8中新增的功能。它们让您无需编写类即可使用状态和其他React功能。前言楼主最近在整理一些关于ReactHooks的资料,为项目重构做准备。下午看完这篇文章。如果你之前没有接触过相关概念,那么通过这篇文章,你将了解ReactHooks是什么,它有什么作用,以及如何使用它。下面我将用一个具体的例子来说明。通过这个例子,你会明白:如何使用ReactHooks以及如何使用ReactClass组件来实现同样的逻辑快速入门首先,快速搭建一个项目:npxcreate-react-appexploring-hooksDemoinsetStateimportReact,{Component}来自“反应”;exportdefaultclassButtonextendsComponent{state={buttonText:"Clickme,please"};handleClick=()=>{this.setState(()=>{return{buttonText:"谢谢,被点击了!"};});};render(){const{buttonText}=this.state;返回{buttonText};}}function非常简单:当按钮被点击时,按钮的文本被更新。DemoinHooks在这里,我们将不再使用setState和ES6Class。轮到我们的Hooks登场了:importReact,{useState}from"react";useState的引入意味着我们将在组件内部进行一些状态管理,而我们的React组件将不再是一个ES6类,而是一个简单的纯函数。引入useState后,我们会取出一个包含两个元素的数组:const[buttonText,setButtonText]=useState("Clickme,please");如果对这个语法有疑惑,可以参考ES6解构。这两个values的名字,你可以随便取,跟React无关,但是建议你根据使用目的选择一个足够具体、足够清晰的名字。上面写的,一个代表buttonText的值,一个代表setButtonText的update函数。useState的输入是一个初始值,比如这个按钮的初始显示是:Clickme,please。这个简单示例的完整代码:importReact,{useState}from"react";exportdefaultfunctionButton(){const[buttonText,setButtonText]=useState("请点击我");functionhandleButtonClick(){returnsetButtonText("谢谢,被点击了!");}return{buttonText};}接下来介绍如何使用Hooks获取数据。使用ReactHooks获取数据在这之前,我们都是在componentDidMount函数中调用API:importReact,{Component}from"react";exportdefaultclassDataLoaderextendsComponent{state={data:[]};asynccomponentDidMount(){try{constresponse=awaitfetch(`https://api.coinmarketcap.com/v1/ticker/?limit=10`);如果(!response.ok){抛出错误(response.statusText);}constjson=awaitresponse.json();this.setState({数据:json});}赶上(错误){console.log(错误);}}render(){return({this.state.data.map(el=>({el.name}))}
);}}这种代码想必大家都很熟悉了,下面我们用Hooks重写一下:importReact,{useState,useEffect}from"react";导出默认函数DataLoader(){const[data,setData]=useState([]);useEffect(()=>{fetch("http://localhost:3001/links/").then(响应=>response.json()).then(data=>setData(data));});返回({data.map(el=>({el.title}))}
);}运行之后你会发现,哎呀,报错了,死循环:原因其实很简单,useEffect和componentDidMount、componentDidUpdate、componentWillUnmount的目的是一致的,每次state变化或者新的props进来,componentDidUpdatecomponentDidUpdate`会被执行要解决这个“bug”也很简单,传递一个空数组给useEffect作为第二个参数:useEffect(()=>{fetch("http://localhost:3001/links/").then(response=>response.json()).then(data=>setData(data));},[]);//<<超级重要的数组关于Hook的更多信息,请参考:使用EffectHook你可能看到这里按捺不住心中的小火,想要重构项目。我个人不建议这样做,因为在接下来的几个版本中可能会有变化,就像RyanFlorence所建议的:HooksarenottheendgameforReactdataloading.Dataloadingprobablythemostcommoneffectinaapp.不要急于迁移到数据的钩子上,除非你可以在数据悬念稳定时再次迁移。控制你的客户流失率。—RyanFlorence(@ryanflorence)2019年2月12日无论如何,useEffect的出现是一件好事。Hooks可以用于Render道具吗?显然是的,但是没有意义。例如,更改上面的代码:importReact,{useState,useEffect}from"react";导出默认函数DataLoader(props){const[data,setData]=useState([]);useEffect(()=>{fetch("http://localhost:3001/links/").then(response=>response.json()).then(data=>setData(data));},[]);returnprops.render(data)}从外面传入一个render就可以了,但是这是没有意义的:ReackHooks本身就是为了解决组件之间的公共逻辑问题。定义你的ReactHook或上面的例子,我们提取获取数据的逻辑://useFetch.tsximport{useState,useEffect}from"react";导出默认函数useFetch(url){const[data,setData]=useState([]);useEffect(()=>{fetch(url).then(response=>response.json()).then(data=>setData(data));},[]);returndata;}其他组件中的引用:importReactfrom"react";importuseFetchfrom"./useFetch";exportdefaultfunctionDataLoader(props){constdata=useFetch("http://localhost:3001/links/");return({data.map(el=>({el.title}))}
);}ReactHooks的本质上面我们提到,ReackHooks本身就是为了解决组件之间的公共逻辑问题。回头看我们现在的做法,几乎都是面向生命周期的编程:Hooks的出现就是把这种面向生命周期的编程变成面向业务逻辑的编程,这样我们就不用关注lifecycle:imagesource并且,在最新的React中,预置了大量的Hooks,其中最重要的两个Hooks:useState和useEffect.useState使得我们可以在组件内部使用state而无需借助ES6类。useEffect替代componentDidMount、componentDidUpdate、componentWillUnmount,提供统一的API。除了这两个,你还可以在官方文档中了解更多:一个显而易见的事实是,在短时间内,我们将有三种创建React组件的姿势:函数式组件class组件带有hooks的函数式组件作为一个React忠实粉丝,它有很高兴看到这些积极的变化。Hooks还有很多学习资源可以帮助我们更好的学习和掌握ReactHooks,这里分享一下:首先官方文档:IntroducingHooks,HooksataGlance是比较深入一点的内容。然后是入门教程:BuildaCRUDAppinReactwithHooks。关于状态管理,还有一篇很有意思的文章:useReducer,don'tuseState比较有意思的是,最后我们会大量使用useReducer,情况和Redux很像:functionreducer(state,action){const{过去,未来,现在}=状态切换(动作类型){case'UNDO':constprevious=past[past.length-1]constnewPast=past.slice(0,past.length-1)return{past:newPast,present:previous,future:[present,...future],}case'REDO':constnext=future[0]constnewFuture=future.slice(1)返回{past:[...past,present],present:next,future:newFuture,}default:returnstate}}这也从侧面证明了Redux在社区的影响力(其实这两个东西的核心开发都是同一个人)。总结Hooks的出现简化了逻辑,将面向生命周期的编程变成了面向业务逻辑的编程,为逻辑复用提供了更多可能。钩子是未来的方式。大概就这些吧,希望对你有所启发和帮助。文中如有错误,请帮我指正,谢谢。