React Hooks
#积累/react/react-hooks#
无状态组件
1 | const Header = props => <p>...</p> |
当写着无状态组件,发现需要使用state,需要使用生命周期的时候,必须转换为class组件。现在有了另外一个选择,React Hooks。
React Hooks提供了一种方法,在原来的无状态组件中使用state、生命周期等React特性。
-无状态组件- => 函数组件
React Hooks的简单例子
1 | function UserGreetings(props) { |
1 | //使用 |
特性:
- UserGreetings组件不仅会因为props的改变而重新渲染,通过useState创建的状态的改变也会导致组件重新渲染。
- useState的作用,挂载时创建,重新渲染都是读取。
- UserGreetings组件渲染到屏幕之后会执行useEffect中的函数;useEffect可以返回一个清除函数,它会在组件重新渲染前执行。默认每次渲染,effect都会被清除并重新创建;
1
2
3
4
5
6
7
8
9useEffect(
() => {
const subscription = props.source.subscribe();
return () => {
subscription.unsubscribe();
};
},
[props.source],
);
可以传入一个依赖数组,作为第二参数,只有当数组中的状态变化,才会重新创建effect;
传入一个空数组作为第二参数,则只会在组件挂载和卸载时执行。
自定义Hook
- React 内置的Hook API:
- 简单例子:使用自定义Hook
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}特性:1
2
3
4
5
6
7
8function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
- 自定义Hook的命名以“use”开头。
- useFriendStatus返回的isOnline,它的改变,会引起FriendStatus的重新渲染。可以理解为通过自定义Hook间接调用了useState、useEffect。
- 自定义Hook只是个函数,可以用来计算state、执行effect,等任何内置Hook行为逻辑的分隔。
Hook VS Class
React Hooks和class组件可以实现几乎一样的功能,其意义何在?
Why Hooks?
However, we often can’t break complex components down any further because the logic is stateful and can’t be extracted to a function or another component.
我们经常不能将复杂组件分解地足够小,因为逻辑是有状态的;状态不能被提取到单独的函数或组件中,状态只能按层级传递。当我们尝试用独立组件的方式解决这些问题,我们总是止步于:
1.巨大的组件很难重构和测试;
2.两个不同组件间重复的逻辑和生命周期方法;
3.像render props和高阶组件的模式太复杂。
我们认为Hooks是解决这些问题最好的办法。Hooks让我们把逻辑的组织从组件转移到可重用的独立单元。
What Are Hooks,Exactly?
Components are more powerful, but they have to render some UI. This makes them inconvenient for sharing non-visual logic.
This is how we end up with complex patterns like render props and higher-order components.Wouldn’t React be simpler if there was justonecommon way to reuse code instead of so many?
组件更加强大,但它必须渲染一些UI。这使得它复用非视觉逻辑不方便。
这就是为什么我们使用像render props和高阶组件这样的复杂模式。
React是否能只用一种通用的方法去复用代码,代替render props和高阶组件这种复杂的模式?
Functions seem to be a perfect mechanism for code reuse. Moving logic between functions takes the least amount of effort. However, functions can’t have local React state inside them. You can’t extract behavior like “watch window size and update the state” or “animate a value over time” from a class component without restructuring your code or introducing an abstraction like Observables. Both approaches hurt the simplicity that we like about React.
函数似乎是代码复用最好的机制。花最少的力气就可以在函数间移动逻辑。但是在函数内部没有本地React状态。在不重构你的代码或引入一个Observables抽象的情况下,你不能抽取像“监听窗口大小,更新状态”或“给一个值随时间产生动画”的行为。两种方式都有损于React的简单性。
Hooks solve exactly that problem. Hooks let you use React features (like state) from a function — by doing a single function call. React provides a few built-in Hooks exposing the “building blocks” of React: state, lifecycle, and context.
Hooks准确地解决了这类问题。通过简单的函数调用,Hooks让你能在函数中使用React特性。React在代码块中提供一些内置Hooks,暴露React的“building blocks”,像state, lifecycle, and context。
React Hooks实现组件生命周期
React Hooks重要的两条原则
::只在 React 函数中调用 Hook::
不要在普通的 JavaScript 函数中调用 Hook,Hook提供的功能需要在组件的环境下才有意义。
::只在最顶层使用 Hook::
不要在循环,条件或嵌套函数中调用 Hook
为什么顺序对React Hook很重要
其他
- 不能在class中调用Hooks,只能在class中引入函数组件。
Invariant Violation
Hooks can only be called inside the body of a function component.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class App extends Component {
constructor(props) {
super(props);
}
render() {
const element = hovered => <div>Hover me! {hovered && "Thanks!"}</div>;
const [hoverable, hovered] = useHover(element);
return (
<div>
{hoverable}
<div>{hovered ? "HOVERED" : ""}</div>
</div>
);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15const Demo = () => {
const element = hovered => <div>Hover me! {hovered && "Thanks!"}</div>;
const [hoverable, hovered] = useHover(element);
return (
<div>
{hoverable}
<div>{hovered ? "HOVERED" : ""}</div>
</div>
);
};
class App extends Component {
render() {
return <Demo />;
}
} - https://github.com/acdlite/recompose
- Spread Love, NotHype
When you talk to other people who aren’t as excited as you are, please be courteous. If you see a misconception, you can share extra information if the other person is open to it. But any change is scary, and as a community we should try our best to help people instead of alienating them. And if I (or anyone else on the React team) fail to follow this advice, please call us out! - React Hooks一些自定义Hook,usehooks.com