官方文档:https://react.docschina.org/docs/hooks-intro.html
Hook
是 React 16.8 的新增特性。它可以让你在不编写 class
的情况下使用 state
以及其他的 React
特性。
Hook 的作用位置
复习一下, React 的函数组件是这样的:
const Example = (props) => {
// 你可以在这使用 Hook
return <div />;
}
或是这样:
function Example(props) {
// 你可以在这使用 Hook
return <div />;
}
Hook
的作用范围就在上诉的函数组件之内,之前我们可能把它们叫做“无状态组件”。但现在我们为它们引入了使用 React state
的能力,所以我们更喜欢叫它”函数组件”。
Hook
在 class
内部是不起作用的。
State Hook
用一个计数器的简单例子来说明:
import React, { useState } from 'react'
import ReactDOM from 'react-dom'
function Example() {
// 相当于声明一个叫 “count” 的 state 变量
// setCount 为设定变量 count 的函数
// useState(0) 设定了 count 的默认值为 0
// 注意:count,setCount 都是可以自定义命名的,并非 useState 自身的 API
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
ReactDOM.render(
<Example />,
document.getElementById('root')
)
上述代码产生了一个简单的点击就 +1 的计数器组件。
通过使用 useState
我们无需使用 class
就可以使用 state
的特性,如果要用 class
来实现上面操作,会是这样:
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
声明多个 State Hook
你可以在一个组件中多次使用 State Hook
:
function ExampleWithManyStates() {
// 声明多个 state 变量!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
// ...
}
带参数的函数
下例中,我们可以通过参数来决定,数目增加的多数。
function App() {
const [count, setCount] = useState(0);
const handalClick = (num) => () => {
setCount(count + num)
};
return (
<div>
<p>You clicked {count} times</p>
<button onClick={handalClick(10)}>
+ 10
</button>
</div>
);
}
Effect Hook
useEffect
是一个 Effect Hook
,给函数组件增加了操作副作用的能力。它跟 class
组件中的 componentDidMount
、componentDidUpdate
和 componentWillUnmount
具有相同的用途,只不过被合并成了一个 API。
下面用一个例子演示,在组件挂载时和组件更新时,会更新 HTML 的 title
。
import React, { useState, useEffect } from 'react'
import ReactDOM from 'react-dom'
function Example() {
const [count, setCount] = useState(0);
// 相当于 componentDidMount 和 componentDidUpdate:
useEffect(() => {
// 使用浏览器的 API 更新页面标题
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
ReactDOM.render(
<Example />,
document.getElementById('root')
)
当你调用 useEffect
时,就是在告诉 React 在完成对 DOM
的更改后运行你的 useEffect
里的函数。默认情况下,React 会在每次渲染后调用副作用函数 ,包括第一次渲染。
由于副作用函数是在组件内声明的,所以它们可以访问到组件的 props
和 state
。
useEffect
函数还可以通过返回一个函数,来指定组件销毁阶段的操作。
function Example() {
const [count, setCount] = useState(0);
// 相当于 componentDidMount 和 componentDidUpdate:
useEffect(() => {
// 使用浏览器的 API 更新页面标题
document.title = `You clicked ${count} times`;
// 这部分代码组件第一次渲染时不执行
// 组件更新前的销毁阶段执行,相当于 componentWillUnmount
return () => {
console.log('组件销毁')
};
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
通过跳过 Effect 进行性能优化
function Example() {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
useEffect(() => {
console.log(`You clicked button-1 ${count1} times`);
}, [count1]); // 只有 count1 更新时才执行
useEffect(() => {
console.log(`You clicked button-2 ${count2} times`);
}, [count2]); // 只有 count2 更新时才执行
return (
<div>
<p>You clicked button-1 {count1} times</p>
<p>You clicked button-2 {count2} times</p>
<button onClick={() => setCount1(count1 + 1)}>
Click 1
</button>
<button onClick={() => setCount2(count2 + 1)}>
Click 2
</button>
</div>
);
}
上述代码演示了限制特定的 state
变化再触发 useEffect
函数的执行。
如果 useEffect
的第二个参数为空数组,则该 useEffect
函数只在第一次渲染时候执行。
useEffect(() => {
console.log(`start`);
}, []); //只在第一次渲染时候执行
网友评论