Skip to content

Commit 12ad856

Browse files
committed
Bunch of tweaks
1 parent 8054d8a commit 12ad856

File tree

19 files changed

+457
-272
lines changed

19 files changed

+457
-272
lines changed

lessons/03-controlled-components/lecture/Minutes.js

+6-21
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ import { FaMinus, FaPlus } from "react-icons/fa"
1212
// In practical terms, an uncontrolled component is one whose value is changed
1313
// exclusively by the *user interacting with it*.
1414
//
15-
// You can still set the initial state of an uncontrolled component with
15+
// You can still set the initial state of an uncontrolled component with
1616
// defaultValue (and defaultChecked).
1717
//
1818
// A controlled component is one that does not own its state, but rather its
19-
// state is controlled by the component that rendered it.
19+
// state is controlled by the component that rendered it.
2020
//
2121
// In practical terms it means the state is controlled exclusively by the
2222
// *programmer*.
@@ -25,7 +25,7 @@ import { FaMinus, FaPlus } from "react-icons/fa"
2525
// value of an input by some other means than the user interacting with it.
2626
//
2727
// If you need the value of a component in your state, but you don't ever set
28-
// the value of the component with anything other thant he user interacting
28+
// the value of the component with anything other than the user interacting
2929
// with it, you can use either controlled or uncontrolled, it's the same. We
3030
// prefer uncontrolled in these situations just to communicate intent.
3131

@@ -37,23 +37,13 @@ export default function Minutes({ date }) {
3737
return (
3838
<div className="Minutes">
3939
<div>
40-
<button
41-
type="button"
42-
className="icon_button Minutes_button"
43-
>
40+
<button type="button" className="icon_button Minutes_button">
4441
<FaMinus />
4542
</button>
4643
</div>
47-
<input
48-
className="Minutes_input"
49-
defaultValue={0}
50-
id="minutes"
51-
/>
44+
<input className="Minutes_input" defaultValue={0} id="minutes" />
5245
<div>
53-
<button
54-
type="button"
55-
className="icon_button Minutes_button"
56-
>
46+
<button type="button" className="icon_button Minutes_button">
5747
<FaPlus />
5848
</button>
5949
</div>
@@ -64,7 +54,6 @@ export default function Minutes({ date }) {
6454
)
6555
}
6656

67-
6857
/******************************************************************************/
6958
// We want these two buttons to change the value of the input, but it doesn't
7059
// work when we use defaultValue, we need to use value.
@@ -112,8 +101,6 @@ export default function Minutes({ date }) {
112101
// )
113102
// }
114103

115-
116-
117104
/******************************************************************************/
118105
// But when we use defaultValue then the user can't type into the input
119106
// anymore. Why does that make sense? React eliminates time. It's declarative.
@@ -297,7 +284,6 @@ export default function Minutes({ date }) {
297284
// }
298285
// }
299286

300-
301287
// return (
302288
// <div className="Minutes">
303289
// <div>
@@ -332,4 +318,3 @@ export default function Minutes({ date }) {
332318
// </div>
333319
// )
334320
// }
335-

lessons/04-effects/exercise/NewPost.final.js

+22-15
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,43 @@
1-
import React, { useState, useEffect, useRef } from "react"
2-
import { useAppState } from "app/app-state"
3-
import Avatar from "app/Avatar"
4-
import Minutes from "app/Minutes"
5-
import { FaDumbbell } from "react-icons/fa"
6-
import RecentPostsDropdown from "app/RecentPostsDropdown"
7-
import { formatDate, DATE_FORMAT } from "app/utils"
1+
import React, { useState, useEffect, useRef } from 'react'
2+
import { FaDumbbell } from 'react-icons/fa'
3+
4+
import { useAppState } from 'app/app-state'
5+
import { formatDate, DATE_FORMAT } from 'app/utils'
6+
import Avatar from 'app/Avatar'
7+
import Minutes from 'app/Minutes'
8+
import RecentPostsDropdown from 'app/RecentPostsDropdown'
89

910
const MAX_MESSAGE_LENGTH = 200
1011

1112
export default function NewPost({ takeFocus, date, showAvatar }) {
12-
const storageKey = makeNewPostKey(date)
1313
const [{ auth }] = useAppState()
14-
const [message, setMessage] = useState(getLocalStorageValue(storageKey) || "")
14+
const [message, setMessage] = useState('')
1515
const messageTooLong = message.length > MAX_MESSAGE_LENGTH
1616
const messageRef = useRef()
1717

18-
const handleMessageChange = event => {
18+
function handleMessageChange(event) {
1919
setMessage(event.target.value)
2020
}
2121

22+
const storageKey = makeNewPostKey(date)
23+
24+
// Initialize the message for this date from the value in storage.
25+
useLayoutEffect(() => {
26+
setMessage(getLocalStorageValue(storageKey) || '')
27+
}, [storageKey])
28+
29+
// Save the message for this date as its value changes.
2230
useEffect(() => {
2331
setLocalStorage(storageKey, message)
24-
}, [message, storageKey])
32+
}, [storageKey, message])
2533

34+
// Automatically focus the <textarea> if it should take focus.
2635
useEffect(() => {
27-
if (takeFocus) {
28-
messageRef.current.focus()
29-
}
36+
if (takeFocus) messageRef.current.focus()
3037
}, [takeFocus, message])
3138

3239
return (
33-
<div className={"NewPost" + (messageTooLong ? " NewPost_error" : "")}>
40+
<div className={'NewPost' + (messageTooLong ? ' NewPost_error' : '')}>
3441
{showAvatar && <Avatar uid={auth.uid} size={70} />}
3542
<form className="NewPost_form">
3643
<textarea

lessons/04-effects/exercise/NewPost.js

+14-13
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
1-
import React, { useState, useEffect, useRef } from "react"
2-
import { useAppState } from "app/app-state"
3-
import Avatar from "app/Avatar"
4-
import Minutes from "app/Minutes"
5-
import { FaDumbbell } from "react-icons/fa"
6-
import RecentPostsDropdown from "app/RecentPostsDropdown"
7-
import { formatDate, DATE_FORMAT } from "app/utils"
1+
import React, { useState, useEffect, useRef } from 'react'
2+
import { FaDumbbell } from 'react-icons/fa'
3+
4+
import { useAppState } from 'app/app-state'
5+
import { formatDate, DATE_FORMAT } from 'app/utils'
6+
import Avatar from 'app/Avatar'
7+
import Minutes from 'app/Minutes'
8+
import RecentPostsDropdown from 'app/RecentPostsDropdown'
89

910
const MAX_MESSAGE_LENGTH = 200
1011

1112
export default function NewPost({ takeFocus, date, onSuccess, showAvatar }) {
1213
const [{ auth }] = useAppState()
13-
const [message, setMessage] = useState("Ran around the lake.")
14+
const [message, setMessage] = useState('Ran around the lake.')
1415
const messageTooLong = message.length > MAX_MESSAGE_LENGTH
1516

16-
const handleMessageChange = event => {
17+
function handleMessageChange(event) {
1718
setMessage(event.target.value)
1819
}
1920

2021
return (
21-
<div className={"NewPost" + (messageTooLong ? " NewPost_error" : "")}>
22+
<div className={'NewPost' + (messageTooLong ? ' NewPost_error' : '')}>
2223
{showAvatar && <Avatar uid={auth.uid} size={70} />}
2324
<form className="NewPost_form">
2425
<textarea
@@ -49,10 +50,10 @@ function makeNewPostKey(date) {
4950
}
5051

5152
function getLocalStorageValue(key) {
52-
const val = localStorage.getItem(key)
53-
if (!val) return null
53+
const value = localStorage.getItem(key)
54+
if (!value) return null
5455
try {
55-
return JSON.parse(val)
56+
return JSON.parse(value)
5657
} catch (e) {
5758
return null
5859
}

lessons/04-effects/exercise/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Effects
22

3-
## Save state to local storag
3+
## Save state to local storage
44

55
Save the message value into localStorage so that if the user accidentally closes the dialog or navigates away from the page, we can bring it back!
66

lessons/04-effects/lecture/Dashboard.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/******************************************************************************/
22
// open NewPost.js
33
import React, { useState, useEffect } from "react"
4+
45
import NewPost from "app/NewPost"
56

67
// import App from "../../../modules/app/App"

0 commit comments

Comments
 (0)