Skip to content

Commit e83b405

Browse files
committed
New react articles :)
1 parent ceb5a1e commit e83b405

File tree

5 files changed

+134
-2
lines changed

5 files changed

+134
-2
lines changed

apps/components_guide_web/lib/components_guide_web/controllers/react_typescript_controller.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ defmodule ComponentsGuideWeb.ReactTypescriptController do
77
|> render("index.html", article: "tips")
88
end
99

10-
@articles ["testing", "forms"]
10+
@articles ["testing", "forms", "event-handlers", "logical-clocks"]
1111

1212
def show(conn, %{"article" => article}) when article in @articles do
1313
render(conn, "index.html", article: article)

apps/components_guide_web/lib/components_guide_web/templates/layout/_contentinfo.html.eex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<footer role="contentinfo" class="container pt-8 pb-6 text-gray-500 border-t border-gray-800 tracking-wide">
1+
<footer role="contentinfo" class="container pt-16 pb-6 text-gray-500 border-t border-gray-800 tracking-wide">
22
<div class="text-center text-xl text-white" style="--link-decoration: underline">
33
Follow <a href="https://twitter.com/ComponentsGuide">@ComponentsGuide</a> on Twitter for the latest articles.
44
</div>

apps/components_guide_web/lib/components_guide_web/templates/react_typescript/_top.html.eex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
<ul y-y x-x=md class="text-lg list-none font-bold" data-links="p-3">
1212
<li><%= link("Fundamentals", to: '/react+typescript') %>
1313
<li><%= link("Testing", to: '/react+typescript/testing') %>
14+
<li><%= link("Event Handlers", to: '/react+typescript/event-handlers') %>
15+
<li><%= link("Logical Clocks", to: '/react+typescript/logical-clocks') %>
1416
<li><%= link("Forms", to: '/react+typescript/forms') %>
1517
</ul>
1618
</nav>
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# React Event Handlers
2+
3+
## Deciding whether to control a form element
4+
5+
- A controlled element lets you have **full control** over its value.
6+
- An uncontrolled element can let you handle events with less code.
7+
8+
## Controlled form elements
9+
10+
- We store the state for each field using `useState`.
11+
- We must set the current `value` of the input when rendering.
12+
- We must listen to when the user changes using `onChange` on each input, and update our state.
13+
- We can then read our state when the form is submitted.
14+
15+
```tsx
16+
import React, { useState } from "react";
17+
import authService from "../services/auth";
18+
19+
function SignInForm() {
20+
const [email, updateEmail] = useState("");
21+
const [password, updatePassword] = useState("");
22+
23+
return (
24+
<form
25+
onSubmit={(event) => {
26+
event.preventDefault(); // Prevent performing normal submission
27+
// Could validate here.
28+
authService.signIn({ email, password });
29+
}}
30+
>
31+
<label>
32+
Email
33+
<input
34+
type="email"
35+
value={email}
36+
onChange={(event) => {
37+
updateEmail(event.target.value);
38+
}}
39+
/>
40+
</label>
41+
<label>
42+
Password
43+
<input
44+
type="password"
45+
value={password}
46+
onChange={(event) => {
47+
updatePassword(event.target.value);
48+
}}
49+
/>
50+
</label>
51+
<button type="submit">Sign In</button>
52+
</form>
53+
);
54+
}
55+
```
56+
57+
## Uncontrolled form elements
58+
59+
- We have no state — the input itself holds the state.
60+
- We could set an initial value using `defaultValue`.
61+
- We don’t have to listen to any change events.
62+
- We can then read from the form using the DOM when it is submitted.
63+
64+
```tsx
65+
import React, { useState } from "react";
66+
import authService from "../services/auth";
67+
68+
function SignInForm() {
69+
return (
70+
<form
71+
onSubmit={(event) => {
72+
event.preventDefault(); // Prevent performing normal submission
73+
const email = event.target.elements.email.value;
74+
const password = event.target.elements.password.value;
75+
// Could validate here.
76+
authService.signIn({ email, password });
77+
}}
78+
>
79+
<label>
80+
Email
81+
<input type="email" name="email" />
82+
</label>
83+
<label>
84+
Password
85+
<input type="password" name="password" />
86+
</label>
87+
<button type="submit">Sign In</button>
88+
</form>
89+
);
90+
}
91+
```
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Simplify React Effects with Logical Clocks
2+
3+
## Problems
4+
5+
Hooks offer a more flexible and powerful suite of tools than we had a few years ago in React with class components’ lifecycle methods.
6+
7+
Each hook tries to follow the unix philosophy: have small tools that solve one particular task well. For example, `useState()` solves many needs for a mutable variable that belongs to a component.
8+
9+
However, while React has certainly made the *what* easier with the declarative model of building a view, getting the *when* right proves to be a lot harder. Hooks like `useEffect()` can appear simple but are difficult to compose together and to visualise. By using logical clocks, we can get back towards the declarative model that we all love in React.
10+
11+
## What is a logical clock?
12+
13+
```ts
14+
function useTick() {
15+
return useReducer(n => n + 1, 0);
16+
}
17+
```
18+
19+
## Debouncing
20+
21+
```ts
22+
export function useDebouncer(duration: number): readonly [number, EffectCallback] {
23+
const [count, tick] = useTick();
24+
const effect = useCallback(() => {
25+
const timeout = setTimeout(tick, duration);
26+
return () => clearTimeout(timeout);
27+
}, [duration, tick]);
28+
29+
return [count, effect];
30+
}
31+
```
32+
33+
```ts
34+
export function useDebouncedEffect(effect: EffectCallback, duration: number, deps: DependencyList): void {
35+
const [count, didChange] = useDebouncer(duration);
36+
useEffect(didChange, deps); // When our deps change, notify our debouncer.
37+
useEffect(effect, [count]); // When our debouncer finishes, run our effect.
38+
}
39+
```

0 commit comments

Comments
 (0)