5分钟学会 React Hooks
这些是什么?
跳进去👟
useState
为什么不上课?📗
其他钩子
useEffect
关注点分离
创建自定义钩子
应该做的事👍
注意事项👎
注意事项⚠️
就是这样!
这些是什么?
一组函数,为我们在实例上访问的方法提供直接 API Component
。我们可以创建有状态组件,或者在没有实例的情况下访问组件的生命周期class
🎉
对于那些TL;DR阵营的人来说,向下滚动查看一系列演示👍
跳进去👟
考虑一下这个选择并显示颜色值的应用程序🎨
我们需要一个class
实例来添加state
。
const colors = {
Sea: '#a2ccb6',
Sand: '#fc22b5',
Peach: '#ee786e',
}
class App extends Component {
state = {
color: colors.Sea,
}
render = () => {
const { color } = this.state
return (
<Fragment>
<select
value={color}
onChange={e => this.setState({color: e.target.value})}
>
{ Object.entries(colors).map(c => (
<option key={`color--${c[0]}`} value={c[1]}>
{c[0]}
</option>
))}
</select>
<h2>{`Hex: ${color}`}</h2>
</Fragment>
)
}
}
但带钩子
const { useState } = React
const App = () => {
const [color, setColor] = useState(colors.Sea)
return (
<Fragment>
<select value={color} onChange={e => setColor(e.target.value)}>
{Object.entries(colors).map(([name, value]) => (
<option value={value}>{name}</option>
))}
</select>
<h1>{`Hex: ${color}`}</h1>
</Fragment>
)
}
useState
是一个允许我们使用和更新状态值的钩子。
useState
该useState
钩子提供了一个状态值以及更新它的方法。参数是默认值。该值也可以是任意类型!👍
不需要class
实例🙌
不要害怕这种语法。useState
利用Array
解构。
它等于
const state = useState(Colors.Sea)
const color = state[0]
const setColor = state[1]
为什么不上课?📗
- 缩小效果并不好。
- 当课程试图承担过多内容时,就会失去背景。
- 生命周期方法中的关注点分离不佳。
- 需要对属性进行不稳定的语法转换
class
。 - HMR 问题。
- 主观用例,何时使用而不是无状态函数。
如果课程适合您,则无需更改。Hooks 不会取代课程。
其他钩子
有几种钩子。你可能最常使用的钩子是useState
和useEffect
。其他钩子请参阅钩子参考。
useEffect
当我们想要进入生命周期阶段时,我们会使用这个钩子。
useEffect === componentDidMount + componentDidUpdate + componentWillUnmount
我们将一个函数传递给useEffect
在每次渲染上运行的钩子。
让我们使用 来更新我们之前的颜色选择应用程序useEffect
。
const App = () => {
const [color, setColor] = useState(colors.Sea)
useEffect(
() => {
document.body.style.background = color
}
)
return (
<Fragment>
<select value={color} onChange={e => setColor(e.target.value)}>
{Object.entries(colors).map(([name, value]) => (
<option key={`color--${name}`} value={value}>
{name}
</option>
))}
</select>
<h1>{color}</h1>
</Fragment>
)
}
现在当状态更新时,主体颜色将会改变👍
每次渲染都会运行?没错。不过,它并非必须如此。 有一个可选的第二个参数useEffect
。您可以传递一个Array
值,如果这些值在渲染期间没有变化,则效果将不会执行。空Array
表示效果只运行一次。但在大多数情况下,有更好的解决方案来实现这个结果,
useEffect(
() => {
document.body.style.background = color
},
[color]
)
现在我们只在发生变化时设置背景color
👍在这个例子中,它仍然会运行每个渲染,因为这color
是触发渲染的唯一事物。
如果我们有第二个状态值,我们就能看到这个可选参数的实际作用。让我们添加一个在按钮点击时递增的计数器值。
const App = () => {
const [color, setColor] = useState(colors.Sea)
const [count, setCount] = useState(0)
// Only run when color is updated 👍
useEffect(
() => {
console.info('Color changed')
document.body.style.background = color
},
[color]
)
return (
<Fragment>
<select value={color} onChange={e => setColor(e.target.value)}>
{Object.entries(colors).map(([name, value]) => (
<option key={`color--${name}`} value={value}>
{name}
</option>
))}
</select>
<h1>{color}</h1>
<h1>{`Count: ${count}`}</h1>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
</Fragment>
)
}
console.info
仅当颜色改变时才会触发👍
其他效果(例如发出 API 请求或绑定用户输入)怎么样?
让我们制作一个跟踪鼠标移动的小应用程序。
我们利用useEffect
绑定鼠标移动来更新一些状态值。
const App = () => {
const [x, setX] = useState()
const [y, setY] = useState()
useEffect(
() => {
const update = (e) => {
setX(e.x)
setY(e.y)
}
window.addEventListener('mousemove', update)
},
[]
)
return x && y ? (<h1>{`x: ${x}; y: ${y};`}</h1>) : null
}
如果组件卸载了,该如何清除绑定?我们可以从useEffect
函数中返回一个函数来进行清理。
useEffect(
() => {
const update = (e) => {
setX(e.x)
setY(e.y)
}
window.addEventListener('mousemove', update)
return () => {
window.removeEventListener('mousemove', update)
}
},
[]
)
不错👊
关注点分离
钩子使我们能够更好地分离关注点。
您是否曾经见过class
似乎有很多事情要做的生命周期方法?
componentDidMount = () => {
makeSomeAPIRequest()
makeOtherAPIRequest()
bindTouchListener()
bindClickEvents()
doOtherUnrelatedStuff()
}
我们可以用钩子来避免这种情况。只要我们的钩子位于顶层,我们就可以随意使用。
考虑更新我们的应用,使其也监听resize
事件。我们不需要在我们的mousemove
效果中实现这一点。我们可以创建一个单独的效果。这是一个值得养成的好习惯,尤其是在我们开始创建自定义钩子的时候。
const App = () => {
const [dimensions, setDimensions] = useState(getDimensions())
const [x, setX] = useState()
const [y, setY] = useState()
// Effect for mousemove
useEffect(
() => {
const update = e => {
setX(e.x)
setY(e.y)
}
window.addEventListener('mousemove', update)
return () => {
window.removeEventListener('mousemove', update)
}
},
[]
)
// Effect for window resizing
useEffect(
() => {
const updateSize = () => setDimensions(getDimensions())
window.addEventListener('resize', updateSize)
return () => {
window.removeEventListener('resize', updateSize)
}
},
[]
)
return (
<Fragment>
{x && y && <h1>{`x: ${x}; y: ${y};`}</h1>}
<h1>
{`Height: ${dimensions.height}; Width: ${dimensions.width};`}
</h1>
</Fragment>
)
}
这是一个演示👍
创建自定义钩子
最后一个示例中的组件开始增长了。Hook 最棒的特性之一就是我们可以将其用法提取到自定义 hooks 中。
这是 Hooks 的一大卖点。你可能对 props 很熟悉Higher Order Components
。render
我们经常需要某种难以维护或论证的结构或风格。但使用 Hooks 则不会出现这种情况。
考虑一下我们的例子。在我们的应用中,跟踪鼠标移动可能很常见。共享这种逻辑是理想的选择。那就开始吧!
const useMousePosition = () => {
const [x, setX] = useState()
const [y, setY] = useState()
useEffect(
() => {
const update = e => {
setX(e.x)
setY(e.y)
}
window.addEventListener('mousemove', update)
return () => {
window.removeEventListener('mousemove', update)
}
},
[]
)
return { x, y }
}
注意我们新的自定义钩子是如何返回当前状态值的。现在任何组件都可以使用这个自定义钩子来获取鼠标位置。
const App = () => {
const { x, y } = useMousePosition()
return x && y ? <h1>{`x: ${x}; y: ${y};`}</h1> : null
}
现在我们有了可以在其他组件之间共享的逻辑💪
让我们考虑另一个例子。我们有各种各样的手表。它们看起来不同,但都使用相同的时间⌚️我们可以自定义一个钩子来获取时间。以下是一个例子;
应该做的事👍
- 当你需要连接到状态或生命周期阶段时使用
- 使用钩子分离关注点
注意事项👎
- 在循环中使用
- 将它们嵌套
- 根据条件使用它们。
注意事项⚠️
- 从react@16.7.0-alpha开始可用
- 没有重大变化🙌
- eslint-plugin-react-hooks@next 👍
就是这样!
5 分钟介绍 React Hooks!
进一步了解➡️
获取所有代码➡️
一如既往,如果您有任何问题或建议,请随时留言或发推文给我🐦!记得在社交媒体上关注我!😎
文章来源:https://dev.to/jh3y/react-hooks-in-5-minutes-55ic