共计 3024 个字符,预计需要花费 8 分钟才能阅读完成。
快来退出咱们吧!
“ 小和山的菜鸟们 ”,为前端开发者提供技术相干资讯以及系列根底文章。为更好的用户体验,请您移至咱们官网小和山的菜鸟们 (https://xhs-rookies.com/) 进行学习,及时获取最新文章。
“Code tailor”,如果您对咱们文章感兴趣、或是想提一些倡议,微信关注 “小和山的菜鸟们” 公众号,与咱们取的分割,您也能够在微信上观看咱们的文章。每一个倡议或是同意都是对咱们极大的激励!
咱们为什么要学 hooks
React-Hooks 简介
react 为什么要有一个 hooks?
1. 有状态的类组件的复用太麻烦
react
的核心思想就是,将一个页面拆成一堆独立的,可复用的组件,并且用自上而下的单向数据流的模式将这些组件串联起来。但如果你在大型的工作我的项目中用 react
,你会发现你的我的项目中实际上很多 react
组件简短且难以复用。特地是那些 class
的组件,它们自身蕴含了 state
,很难进行复用。
官网举荐解决方案
- 渲染属性 – 应用一个值为函数的
prop
来传递须要动静渲染的nodes
或组件. 如上面的代码能够看到咱们的Provider
组件蕴含了所有跟状态相干的代码,而MyComponent
组件则能够是一个单纯的展现型组件,这样一来Provider
就能够独自复用了
import MyComponent from 'components/myComponent'
class Provider extends React.Component {constructor(props) {super(props)
this.state = {target: 'MyComponent'}
}
render() {return <div>{this.props.render(this.state)}</div>
}
}
<Provider render={(data) => <MyComponent target={data.target} />} />
这个模式叫 Render-Props
.
当然个别状况下,都会被写成上面这样的形式:
<Provider>{(data) => <Cat target={data.target} />}</Provider>
- HOC 高阶组件 – 一个函数承受一个组件作为参数,通过一系列加工后,最初返回一个新的组件. 看上面的代码示例,
withUser
函数就是一个高阶组件,它返回了一个新的组件,这个组件具备了它提供的获取用户信息的性能。
const withUser = (WrappedComponent) => {const user = localStorage.getItem('user')
return (props) => <WrappedComponent user={user} {...props} />
}
const UserPage = (props) => (
<div class="user-page">
<p>I'm the user, {props.user}!</p>
</div>
)
export default withUser(UserPage)
以上这两种模式看上去都挺不错的,很多库也使用了这样的模式,就像咱们罕用的 React-router
库。然而这两种模式,会减少代码的层级关系。为了体现的显著,能够装置关上 React Devtools 看看代码的组件嵌套,会发现嵌套次数太多太多。
而如果咱们应用 hooks
,那就会简洁很多,没有多余的层级嵌套。把各种想要的性能写成一个一个可复用的自定义 hook
,当你的组件想用什么性能时,间接在组件里调用这个 hook
即可。
2. 生命周期函数外面逻辑比较复杂
咱们通常心愿一个函数只做一件事件,但咱们的生命周期钩子函数里通常同时做了很多事件。比方咱们须要在 componentDidMount
中发动申请获取数据,绑定一些事件监听等等。同时,有时候咱们还须要在 componentDidUpdate
做一遍同样的事件。
当咱们的这个页面或者这个组件,变得复杂的时候,外面的内容就会变多,逻辑的清晰度就会降落。
3.class 中的 this 指向问题
父组件给子组件传递函数时,必须绑定 this
react
中的组件四种绑定this
办法的区别
class App extends React.Component<any, any> {
handleClick2
constructor(props) {super(props)
this.state = {
num: 1,
title: 'react study',
}
this.handleClick2 = this.handleClick1.bind(this)
}
handleClick1() {
this.setState({num: this.state.num + 1,})
}
handleClick3 = () => {
this.setState({num: this.state.num + 1,})
}
render() {
return (
<div>
<h2>Ann, {this.state.num}</h2>
<button onClick={this.handleClick2}>btn1</button>
<button onClick={this.handleClick1.bind(this)}>btn2</button>
<button onClick={() => this.handleClick1()}>btn3</button>
<button onClick={this.handleClick3}>btn4</button>
</div>
)
}
}
- 构造函数中绑定
this
,那么每次父组件刷新的时候,如果传递给子组件其余的props
值不变,那么子组件就不会刷新 render()
函数外面绑定this
:因为bind
函数会返回一个新的函数,所以每次父组件刷新时,都会从新生成一个函数,即便父组件传递给子组件其余的props
值不变,子组件每次都会刷新;()=>{}
箭头函数:父组件刷新的时候,即便两个箭头函数的函数体是一样的,都会生成一个新的箭头函数,所以子组件每次都会刷新;- 应用类的动态属性:原理和第一种办法差不多,比第一种更简洁
综上所述,如果不留神的话,很容易写成第三种写法,导致性能上有所损耗
hooks 长处
- 能优化类组件存在问题
- 能在无需批改组件构造的状况下复用状态逻辑(自定义 Hooks )
- 能将组件中互相关联的局部拆分成更小的函数(比方设置订阅或申请数据)
- 副作用的关注点拆散 : 副作用指那些没有产生在数据向视图转换过程中的逻辑,如
ajax
申请、拜访原生dom
元素、本地长久化缓存、绑定 / 解绑事件、增加订阅、设置定时器、记录日志等。以往这些副作用都是写在类组件生命周期函数中的。而useEffect
在全副渲染结束后才会执行,useLayoutEffect
会在浏览器layout
之后,painting
之前执行。
小结
当初,咱们对 hooks
曾经有了一个大略的理解。
那么之后就开始咱们的根底 hooks
教程了。
在 hooks
系列中,咱们次要介绍四个我的项目中罕用的钩子:useState、useEffect、useRefs、useCallback.
如果你们想要理解一些其余钩子函数(useContext、useReducer、useMemo、useImperativeMethods、useMutationEffect、useLayoutEffect),能够去官网查看。
下节预报
在下节中,咱们将为大家介绍 useState
,敬请期待!