TypeScript and React: Hooks
https://fettblog.eu/typescript-react/hooks/
Hooks đã được công bố tại React Conf 2018. Hãy xem trang này để biết thêm chi tiết. Tôi nghĩ chúng khá tuyệt vời. Có lẽ là thay đổi cuộc chơi! Hooks nâng cao các thành phần chức năng “không trạng thái” trước đây thành… về cơ bản mọi thứ mà các thành phần lớp truyền thống có thể có. Với một API sạch hơn nhiều!
Chỉ nhanh chóng sau khi phát hành trong React 16.7., Các kiểu gõ trong React trong DefiniedlyTyped cũng nhận được bản cập nhật. Kiểm tra cách bạn có thể sử dụng hook với TypeScript!
Tuyên bố từ chối trách nhiệm: Tất cả đều rất thử nghiệm. Tuy nhiên, ngọt ngào.
useState
useState có lẽ là một trong những bạn sẽ sử dụng nhiều. Thay vì sử dụng this.state từ các thành phần lớp, bạn có thể truy cập trạng thái hiện tại của một cá thể thành phần và khởi tạo nó, bằng một lệnh gọi hàm duy nhất. Mong muốn của chúng tôi cho việc nhập liệu mạnh mẽ là các giá trị mà chúng tôi đặt ban đầu, nhận mỗi bản cập nhật thành phần và đặt qua các sự kiện, luôn có cùng một kiểu. Với các kiểu đánh máy được cung cấp, điều này hoạt động mà không cần bất kỳ TypeScript bổ sung nào:
Students and Teachers, save up to 60% on Adobe Creative Cloud.ADS VIA CARBON
Hooks have been announced at React Conf 2018. Check out this page for more details. I think they’re pretty awesome. Probably game-changing! Hooks heave formerly “stateless” functional components to … basically everything traditional class components can be. With a much cleaner API!
Just quickly after their release in React 16.7., React typings in DefinitelyTyped got an update as well. Check out how you can use hooks with TypeScript!
Disclaimer: This is all very experimental. Sweet nonetheless.
In this section:
useState#
useState
is probably one you are going to use a lot. Instead of using this.state
from class components, you can access the current state of a component instance, and initialise it, with one single function call. Our desire for strong typing is that values we initially set, get per component update, and set through events, always have the same type. With the provided typings, this works without any additional TypeScript:
And that’s it. Your code works with out any extra type annotations, but still typechecks.
useEffect#
useEffect
is here for all side effects. Adding event listeners, changing things in the document, fetching data. Everything you would use component lifecycle methods for (componentDidUpdate
, componentDidMount
, componentWillUnmount
) The method signature is pretty straightforward. It accepts two parameters:
A function that is called without any parameters. This is the side-effect you want to call.
An array of values of type
any
. This parameter is optional. If you don’t provide it, the function provided is called every time the component update. If you do, React will check if those values did change, and triggers the function only if there’s a difference.
You don’t need to provide any extra typings. TypeScript will check that the method signature of the function you provide is correct. This function also has a return value (for cleanups). And TypeScript will check that you provide a correct function as well:
This also goes for useLayoutEffect
and useMutationEffect
.
useContext#
useContext
allows you to access context properties from anywhere in your components. Much like the Context.Consumer
does in class components. Type inference works brilliantly here, you don’t need to use any TypeScript specific language features to get everything done:
Again, as it should be!
useRef#
useRef
is nice as you can set references directly in your function components. However, this was the first time I found hooks together with TypeScript a bit tricky! When you are in strict mode, TypeScript might complain:
Here’s what bugs us:
usually we initialise refs with null. This is because we set it later in our JSX calls
with the initial value of a ref being null, inputEl might be null. TypeScript complains that you should do a strict null check.
That’s not the only thing. Since TypeScript doesn’t know which element we want to refer to, things like current
and focus()
will also probably be null. So our strict null checks are pretty elaborate. We can make this a ton easier for us and for TypeScript, when we know which type of element we want to ref. This also helps us to not mix up element types in the end:
A bit more type safety for all of us ❤️
useMemo - useCallback#
You know from useEffect
that you can influence the execution of certain functions by passing some parameters to it. React checks if those parameters have changed, and will execute this function only if there’s a difference.
useMemo
does something similar. Let’s say you have computation heavy methods, and only want to run them when their parameters change, not every time the component updates. useMemo
returns a memoized result, and executes the callback function only when parameters change.
To use that with TypeScript, we want to make sure that the return type from useMemo
is the same as the return type from the callback:
The React typings are pretty good at that, so you don’t have to do much else.
useCallback
is very similar. In fact, it’s a shortcut that can be expressed with useMemo
as well. But it returns a callback function, not a value. Typings work similar:
The key here is: Get your typings right. The React typings do the rest.
useReducer#
Now this is something, isn’t it? The core of Redux and similar state management libraries baked into a hook. Sweet and easy to use. The typings are also pretty straightforward, but let’s look at everything step by step. We take the example from the website, and try to make it type safe.
useReducer
accepts a reducer function and an initial state. The reducer function switches the action.type
property and selects the respective action. Nothing new. It’s just that right now, everything is of type any
. We can change that.
The useReducer
typings are nice as you don’t have to change anything in the usage of useReducer
, but can control everything via type inference from the reducer function. Let’s start by making the actions more type safe. Here’s what we want to avoid:
listening to actions that are not
reset
,increment
ordecrement
Making sure that the
type
property is set.
For that, we create an ActionType
type definition. We use union types to make sure that type
can only be of reset
, increment
or decrement
.
That’s not much to do, to make our actions type safe. If you want to add another action, do it at your type declaration. It’s the same with the state. The useReducer
typings infer state types from the reducer function:
Bottom line#
I think hooks are exciting. I also think that TypeScript’s great generics and type inference features are a perfect match to make your hooks type safe, without doing too much. That’s TypeScript’s greatest strength: Being as little invasive as possible, while getting the most out of it.
Last updated
Was this helpful?