8 |
9 | In `C`, programs have a `main()` function.
10 | It's where programs starts.
11 |
12 | React apps are similar; on the web they start with `ReactDOM.render()`.
13 |
14 | ```js
15 | ReactDOM.render(someReactComponent, someDOMNode);
16 | ```
17 |
18 | ### WTF is ReactDOM?
19 |
20 | React is used all over—web, mobile, desktop, VR, appliances.
21 | Lots of places.
22 |
23 | Instead of stuffing all those smarts into one enormous library,
24 | each platform has a partner library.
25 |
26 | On the web, that's `ReactDOM`.
27 |
28 | We use `React` to create components and `ReactDOM` to render them into the DOM.
29 |
30 | ```jsx
31 | ReactDOM.render(
32 | React.createElement("h1", {}, "Hello 🎄"),
33 | document.getElementById("root")
34 | );
35 | ```
36 |
37 | ## Tinker with it
38 |
39 | Use the window below and play around with `render()`.
40 |
41 | - Comment out the import statements. What errors do you get?
42 | - Change the component type to something other than `h1`.
43 | - Put some values in the empty object (second argument). What happens? What errors do you get?
44 |
45 |
8 |
9 | When you set down with set state, you might think state is set immediately.
10 |
11 | It isn't.
12 |
13 | ```js
14 | this.setState({ count: 1 });
15 | console.log(this.state.count); // <= Probably not what you expected
16 | ```
17 |
18 | ## There's a leak!
19 | `setState` has a naming problem.
20 |
21 | You're right to think that `setState` sets state immediately.
22 | It's in the name.
23 | But only because it beats a more descriptive alternative like `enqueueStateTransition`
24 |
25 | For a technical read of what's going on, read the [setState doc](https://reactjs.org/docs/react-component.html#setstate).
26 |
27 | We're gonna talk about hotdogs.
28 |
29 | ## A fast-food mental model
30 | Food trucks provide a great mental model for `setState`.
31 | Here are some attributes they share:
32 |
33 | #### Asynchronous
34 | Food trucks act **asynchronously**—a big word for _"I move on while they make food."_
35 |
36 | I order.
37 | I pay.
38 | I step back and read twitter.
39 | Other people order and pay.
40 | 5-10 minutes later someone hands me food.
41 |
42 | #### Queued
43 | Orders are **queued** but not a [first-in, first-out queue](https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)).
44 | Food trucks need to be fast so they **batch** and **prioritize**.
45 |
46 | #### Prioritized
47 | You like hot fries? Me too.
48 | So when that fryer timer fires, fry orders get **prioritized**.
49 |
50 | _(say that 5 times fast)_
51 |
52 | #### Batched
53 | While I imagine a chef decisively considering exactly how much Tabouli to garnish my "Lambda Lambda Lambda" with, it's not how food trucks work.
54 |
55 | Scott wipes his sweaty brow, looks ahead, see 5 orders of _Lambda Lambda Lambda_, and they get **batched** for quick processing.
56 |
57 | ## What does this have to do with anything?
58 | `setState` is a food truck.
59 |
60 | Orders get **queued**.
61 | Work gets **batched** and **prioritized** for speed.
62 | And it all happens **asynchronously**.
63 |
64 | On the next render, you can pick-up your piping hot _Lambda Lambda Lambda and fries_.
65 |
66 | ## Tinker with it
67 |
68 | Use the workspace below and play around with the state-setting illustration.
69 |
70 |
8 |
9 | You can't use `if/else` statements in `render.
10 |
11 | ```jsx
12 | render() {
13 | return (
14 |
{/* no if/else */}
15 | )
16 | }
17 | ```
18 |
19 | In those curly-braces, you can only use expressions.
20 | Fortunately, you got a couple options.
21 |
22 | ## Tern or Burn
23 |
24 | The [ternary operator](https://en.wikipedia.org/wiki/Ternary_operation) is a
25 | syntax for conditional expressions.
26 |
27 | ```js
28 | // just like if/else
29 | someCondition ? 'shown if truthy' : 'shown if falsy'
30 | ```
31 |
32 | ## Short circuit
33 |
34 | [Short-circuit evaluation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Short-circuit_evaluation) works too.
35 |
36 | ```js
37 | someCondition && 'shown only if truthy' // if
38 | someCondition || 'shown only if falsy' // unless
39 | ```
40 |
41 | ## Clap on, clap off, The Clapper
42 |
43 | Our `ClapCounter` (from [the 9th](/2017/9)) acts like every clap is the first clap.
44 | It just isn't true.
45 |
46 | Let's use short-circuit evaluation render the message _only_ when there are `0` claps.
47 | Let's also render the number of claps _only_ when there are `1` or more.
48 |
49 | ```jsx
50 |
51 |
54 |
55 | {this.state.clapCount === 0 && be the first to clap}
56 |
57 | ```
58 |
59 | ## Tinker with it
60 |
61 | Use the workspace below and explore conditional rendering.
62 | * Use a ternary to add an alternative message _(`condition ? truthy : falsy`)_
63 | * Get crazy and use what we've learned about [events](/2017/6/) and [state](/2017/7/) to conditionally display a message on hover. You can do it!
64 |
65 |
8 |
9 | **Compose** means "smoosh things together."
10 |
11 | You can **smoosh** 🥛 and ☕️.
12 |
13 | You can **smoosh** a 🍔 with your 😋.
14 |
15 | You **smoosh** things all day; it's not fancy.
16 |
17 | ## Copy HTML
18 |
19 | HTML is **smooshable** by default.
20 |
21 | ```html
22 |
23 | Tilted Heading
24 |
25 | ```
26 |
27 |
28 |
29 | The `h1` and `em` are **smooshed**.
30 |
31 | But if we try and **smoosh** things with our `ClapCounter`, nothing happens.
32 |
33 | ```jsx
34 |
35 |
Clap This!
36 |
37 | ```
38 |
39 |
40 | Y U NO SMOOSH?
41 |
42 | ## Meet `children`
43 |
44 | All react components get a special prop: `children`.
45 |
46 | Up to this point, we've had no `children`.
47 | But the stork delivered one when we nested `
Clap This!
` in ``.
48 |
49 | ## Smooshing
50 |
51 | Now that we have `children`, we can `render` them.
52 | Let's put them at the top.
53 |
54 | ```jsx
55 | class ClapCounter extends React.Component {
56 | render () {
57 |
58 | {this.props.children}
59 |
60 | ...
61 | ```
62 |
63 |
64 | Congrats! You learned how to **smoosh**.
65 |
66 | We'll do more advanced **smooshing** next week.
67 |
68 | ## Tinker with it
69 |
70 | Use the workspace below and explore **smooshing**.
71 | * What happens if you keep the `{this.props.children}` but remove the nested `
`?
72 | * Can you smoosh another custom component in `ClapCounter`? Make one and find out.
73 |
74 |
8 |
9 | Today, we start with a new component!
10 |
11 | 🎊 🎉 🎊 🎉
12 |
13 | ## Pokemon
14 |
15 | Take a stab at writing this component
16 | [in a new sandbox](https://codesandbox.io/s/new) before reading the next
17 | section.
18 |
19 | * Name the component `Pokemon`
20 | * Make sure it's a component that can hold [`state`](/2017/7/)
21 | * Use `{ character: null }` as the initial state
22 | * Take an `id` [prop](/2017/4). It'll be the index of the Pokemon we fetch.
23 | * Render [conditionally](/2017/11):
24 | * If `state` has a `character`, render `this.state.character.name`
25 | * Otherwise render the message `...loading`
26 |
27 | _(At this point, it should always render `...loading`)_
28 |
29 | ## Fetch a Pokemon
30 |
31 | You got it? Great!
32 |
33 | In the workspace below, I've included a `fetchPokemon` function. We'll use it in
34 | the next section.
35 |
36 | ## Meet `componentDidMount`
37 |
38 | `componentDidMount` is a [special power](/2017/5) our component has. Speaking
39 | technically, it's a method on our component class.
40 |
41 | When defined, it's called when a `Pokemon` is _mounted_ into the DOM.
42 |
43 | ```jsx
44 | componentDidMount() {
45 | fetchPokemon(1, (character) => this.setState({ character: character }))
46 | }
47 | ```
48 |
49 |
50 |
51 | `componentDidMount` **is the
52 | [ideal place to fetch data from a server.](https://reactjs.org/docs/react-component.html#componentdidmount)**
53 |
54 | ## Tinker with it
55 |
56 | Use the workspace below and explore fetching data in `componentDidMount`:
57 |
58 | * Fetch a pokemon with a different id
59 | * Log messages from `componentDidMount` and `render` observe the order in the
60 | console.
61 |
62 |
8 |
9 | > 99.7% of software development in one requirement
10 | > A user should be able to view a list of items.
11 | > — [@samccone](https://twitter.com/samccone/status/936665335394168837)
12 |
13 | Listen to Sam.
14 | Lists make Apps.
15 |
16 | ## Array of sunshine
17 |
18 | The [`children`](/2017/12/) of a component can be an array.
19 |
20 | ```jsx
21 |
{[1, 2, 3]}
22 | ```
23 |
24 |
25 | The resulting DOM will look like this:
26 |
27 | ```html
28 |
123
29 | ```
30 |
31 |
32 | Because [components are just functions](/2017/3/),
33 | arrays can hold components.
34 |
35 | ```jsx
36 |
{[
one
,
two
]}
37 | ```
38 |
39 |
40 | Resulting in DOM like this:
41 |
42 | ```html
43 |
44 |
one
45 |
two
46 |
47 | ```
48 |
49 | ## Data in, components out
50 |
51 | Let's use `map()` to turn an array of data into an array of components.
52 |
53 | ```js
54 | const countdown = [3, 2, 1];
55 | const millenialCountdown = countdown.map(n => {n} 👏);
56 | ```
57 |
58 |
59 | Let's use that technique to show the `abilities` of our `Pokemon`.
60 |
61 | ```jsx
62 |
67 | ```
68 |
69 |
70 | _(The API is a little redundant here. Sorry)_
71 |
72 |
73 | ## Tinker with it
74 |
75 | Use the workspace below and explore arrays as `children`.
76 | * Inspect the API and render another list you find.
77 | * Arrays have a [lot of methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array). Try filtering or sorting the `abilities`.
78 |
79 |
8 |
9 | [Yesterday](/2017/14/), you might have noticed this console warning pop up with our list.
10 |
11 | 
12 |
13 | ## 👶 Give the `children` keys 🔑
14 |
15 | Following the warning above is simple but it leads some questions.
16 |
17 | Pass a unique `key` prop to each component in our `map()`.
18 |
19 | ```jsx
20 |
{ability.ability.name}
21 | ```
22 |
23 | ## Why is this needed?
24 |
25 | #### 👯♀️👯♂️ Teamwork!
26 |
27 | With arrays, React needs assistance.
28 |
29 | To quickly and accurately identify changed, updated, or deleted items, React uses your provided `key` for diffing.
30 |
31 | ## ❄️ How unique is unique? ❄️
32 |
33 | Keys need to be unique to that array.
34 | `id`s work great, if you got 'em.
35 |
36 | Unfortunately, our `abilities` array doesn't have `id`s.
37 | We can use `ability.name` because we know each ability is only listed once per character.
38 |
39 | ```jsx
40 |
41 | {ability.ability.name}
42 |
43 | ```
44 |
45 |
46 | _(Again, `id` is preferred, when available.)_
47 |
48 | ## 🙅♂️ There's no `i` in team 👯♂️👯♀️
49 |
50 | Avoid using the `map(item, i)` index.
51 | It will make updates unpredictable.
52 |
53 | Disregard this warning (if you must) but know that this is a common place for tricky bugs to creep in.
54 |
55 | ## Tinker with it
56 |
57 | Use the workspace below and explore `keys`.
58 |
59 |
8 |
9 | Today we'll talk about things that **don't** happen!
10 |
11 | ## First, a new component
12 |
13 | I'd like you to write a new component.
14 |
15 | You'll [define this component](/2017/5/) [with some state](/2017/7/) and [event handlers](/2017/6/) for [updating that state](/2017/9/). Here are the instructions:
16 |
17 |
22 |
23 |
24 |
25 | * Name it `PokemonPager`
26 | * Set the initial state to have an `id` of `1`
27 | * Render `state.id` in an `h2` component
28 | * Renders two `button` components:
29 | * Clicking **"Previous"** decrements `id`
30 | * Clicking **"Next"** increments `id`
31 |
32 |
33 |
34 | [Create a new sandbox](https://codesandbox.io/s/new) for your component. Try not to look ahead.
35 |
36 | ⚛️ 💪
37 |
38 | ## World's Worst Pokemon Pager
39 |
40 | You've made a `PokemonPager` but it's a bad one.
41 | That's my fault.
42 |
43 | I forgot that it needs to render a `Pokemon`.
44 | Let's fix that!
45 |
46 | ```jsx
47 | class PokemonPager extends React.Component {
48 | state = { id: 1 }
49 |
50 | render() {
51 |
52 |
{this.state.id}
53 |
54 | ...
55 | ```
56 |
57 |
58 | Now we see a big number `1` above Bulbasaur's name and abilities.
59 |
60 | What happens when we click the buttons?
61 |
62 | ## Where's Ivysaur?!?
63 |
64 | Our number gets incremented but Bulbasaur remains the same.
65 |
66 | The components are updating—we see that in the number—but `Pokemon` isn't changing.
67 |
68 | 🤔
69 |
70 | ## This is where I leave you
71 |
72 | Here's the problem:
73 |
74 | The `Pokemon` component only fetches a Pokemon when it gets `mounted`.
75 | It's only `mounted` once. After that, it's gets `updated`.
76 |
77 | We need to fetch the next Pokemon in one of the [updating lifecycle methods](https://reactjs.org/docs/react-component.html#updating).
78 |
79 | Read the docs on [updating lifecycle methods](https://reactjs.org/docs/react-component.html#updating). Find and use one of the methods to fetch a Pokemon every time the component receives a prop `id`.
80 |
81 | ## Tinker with it
82 |
83 | Use the workspace below and explore updating lifecycle methods.
84 |
85 | Make an attempt and I'll show you my recommendation tomorrow.
86 |
87 | _Read sections above carefully; they subtly suggest the right method. Don't forget that most lifecycle methods take arguments._
88 |
89 |
8 |
9 | Here is some lifecycle wisdom:
10 |
11 | > Always use `Did` methods, unless you shouldn't.
12 |
13 | Confused? Read on for more (confusion).
14 |
15 | ## Why `Did`?
16 |
17 | `Did` methods like `componentDidMount` and `componentDidUpdate` are "safe".
18 | They fire after React finishes its work.
19 | So your futzing won't collide with React's futzing.
20 |
21 | **Use `Did` methods are first choice.**
22 |
23 | ## Why not `Did`?
24 |
25 | Sometimes `Did`s don't do exactly what you need.
26 |
27 | In our `Pokemon` component, using `componentDidUpdate` will fetch and `setState` with a new Pokemon with each update.
28 | That sounds like what we want but isn't.
29 |
30 | New props update `Pokemon` but so does the `setState` calls.
31 | Infinite loops, run!!!
32 |
33 | 🏃♂️ 🏃♀️ 🏃♂️ 🏃♀️
34 |
35 |
36 | We have one of those **"unless you shouldn't"** cases.
37 |
38 | ## Enter `componentWillReceiveProps`
39 |
40 | We need a hero lifecycle method that fires for new props but not new state.
41 | `componentWillReceiveProps` is that hero.
42 |
43 | ```jsx
44 | componentWillReceiveProps(nextProps) {
45 | fetchPokemon(nextProps.id).then(character =>
46 | this.setState({ character: character })
47 | )
48 | }
49 | ```
50 |
51 |
52 | This lifecycle method fires **before** `this.props` is set to the new props.
53 | So we don't use `this.props`.
54 | We use the `nextProps`, which `componentWillReceiveProps` receives as an argument.
55 |
56 | 💥
57 |
58 | You're just gonna have to play with this one...
59 |
60 | ## Tinker with it
61 |
62 | Use the workspace below and explore `componentWillReceiveProps`.
63 | * Compare `this.props` and `nextProps` by logging them.
64 | * Change the local name of `nextProps`. There's nothing special about the name.
65 | * Read [the docs](https://reactjs.org/docs/react-component.html#componentwillreceiveprops). Any other things `componentWillReceiveProps` can do?
66 |
67 |
8 |
9 | Gweneth got it right.
10 | [Conscious Uncoupling](https://goop.com/work/relationships/conscious-uncoupling-2/) is a good (for components).
11 |
12 | Let's explore a new [smooshing](/2017/12) technique that makes `PokemonPager` reusable.
13 |
14 | ## Insert component here
15 |
16 | You can **insert** components into other components via props.
17 |
18 | Because [components are functions](https://react.holiday/2017/3) and JavaScript functions transportable, we can pass components around.
19 |
20 | ```jsx
21 |
22 | ```
23 |
24 |
25 |
26 | The above might be implemented something like this:
27 |
28 | ```jsx
29 | const OtherComponent = () =>
👋
30 |
31 | const SomeComponent = props =>
32 | ```
33 |
34 |
35 |
36 | _(Yes, JSX lets you do that)_
37 |
38 | ## Uncoupling `PokemonPager`
39 |
40 | Our `PokemonPager` doesn't need to be Pokemon specific.
41 | With a little work, it could render anything that takes an `id` prop.
42 |
43 | Let's uncouple it by **inserting** `Pokemon` via a `component` prop.
44 |
45 | ```jsx
46 | ReactDOM.render(
47 | ,
48 | document.getElementById("root")
49 | )
50 | ```
51 |
52 |
53 | Now update the `PokemonPager` to render `this.props.component` where `` is.
54 |
55 | ```jsx
56 |
57 | ```
58 |
59 |
60 | Finally, rename `PokemonPager` to a `IdPager`, wherever you see it.
61 |
62 | ## Smooshing is magic
63 |
64 | We're getting to the good stuff.
65 | **Smooshing** is the magic of React 🧙♂️
66 |
67 | This is the first of three **smooshing** patterns we'll explore this week.
68 |
69 | ## Tinker with it
70 |
71 | Use the workspace below and explore component insertion **smooshing**.
72 | * Create a new component called `ShowId` and **insert** it into `IdPager` where `Pokemon` is now.
73 | * Read the doc on defaultProps. Use your new `ShowId` component as the `defaultProps` for `omponent`.
74 |
75 |
8 |
9 | > I know what my decision is,\
10 | > Which is not to decide.
11 |
12 | Indecision is the best tool you have for **smooshing** components together.
13 |
14 | **Master it.**
15 |
16 | ## Listen to Cinderella; leave a clue
17 |
18 | > I'll just leave him a clue:\
19 | > For example, a shoe.\
20 | > And then see what he'll do.
21 |
22 | [On the Steps of the Palace](https://genius.com/Anna-kendrick-on-the-steps-of-the-palace-annotated),
23 | Cinderella isn't sure what to do. So she leaves a shoe as a clue and lets
24 | the prince decide what to do.
25 |
26 | Let's codify this masterful indecision.
27 |
28 | ```jsx
29 | class AClue extends React.Component {
30 | render() { return this.props.render('a shoe') }
31 | }
32 |
33 | const ThePrince = () =>
34 |
36 |
37 | }
38 | />
39 | ```
40 |
41 |
42 |
43 | If Cinderella were a React developer, she'd prefer **render props**.
44 |
45 | ## A render prop
46 |
47 | Simply, **a render prop** is indecision.
48 | React calls `render()` on a component which delegates to `props.render`.
49 |
50 | The power is in the clues.
51 |
52 | ```js
53 | render() { this.props.render("a clue") }
54 | ```
55 |
56 | ## A fairy-tail refactor of `IdPager`
57 |
58 | Let's refactor `IdPager#render()` to not-decide like Cinderella.
59 |
60 | Start where we render the component.
61 | Give `render` as a prop—
62 | a function that takes **a clue** and returns a component.
63 |
64 | Here, the clue **clue** is `id` and the return is a ``.
65 |
66 | ```jsx
67 | ReactDOM.render(
68 | } />,
69 | document.getElementById("root")
70 | );
71 | ```
72 |
73 |
74 | Component-side, it's simple as calling `props.render` with `state.id`.
75 |
76 | ```jsx
77 |
81 | ```
82 |
83 | ## Why though?
84 |
85 | Using a [component prop](/2017/18) was great first step.
86 | It allowed us to uncouple the component specifics.
87 | But there remained a `prop` coupling around `id`.
88 |
89 | With **render props**, we control all aspects of render.
90 |
91 | ```jsx
92 |
94 |
98 | }
99 | />
100 | ```
101 | ## Tinker with it
102 |
103 | Use the workspace below and explore render props.
104 |
105 | Create a `Character` component that consumes the [Star Wars API](https://swapi.co/).
106 | Render a second `IdPager` that pages through Star Wars `Character`s.
107 |
108 |
8 |
9 | People like to make hay about [JSX](https://facebook.github.io/jsx/).
10 |
11 | Don't get your undies in a bunched. All it does is make these two lines equivalent:
12 |
13 | ```jsx
14 | // No-JSX
15 | React.createElement("h1", {}, "Hello 🎄")
16 |
17 | // YAAAAS!!!-JSX
18 |
Hello 🎄
19 | ```
20 |
21 | ### How does HTML work in JavaScript?
22 |
23 | Don't think of it like HTML, it isn't.
24 |
25 | JSX is just a authoring nice-to-have.
26 | But it's not something that works in the browser.
27 | It must be transformed to `React.createElement()` calls before the browser can run it.
28 | Most apps use projects like [Babel](http://babeljs.io/) or
29 | [TypeScript](http://www.typescriptlang.org/) to handle that.
30 |
31 | ### Why JSX?
32 |
33 | JSX is optional but it has community consensus.
34 | There's a certain harmony to spec'ing React elements in a syntax similar to HTML.
35 |
36 | ### Gotchas
37 |
38 | JSX isn't all 🦄s and 🌈s.
39 |
40 | Lowercase attributes like `class`, `onclick`, `autofocus`, and `tabindex` become camelCased `className`, `onClick`, `autoFocus`, and `tabIndex` respectively.
41 |
42 | They can also take any JavaScript expression.
43 |
44 | This takes time to get used to.
45 | The examples below are identical.
46 |
47 | #### HTML
48 |
49 | ```html
50 |
56 | ```
57 |
58 | #### JSX
59 |
60 | ```jsx
61 |
67 | ```
68 |
69 | #### JS
70 |
71 | ```js
72 | React.createElement(
73 | 'button',
74 | {
75 | type: 'button',
76 | autoFocus: true,
77 | className: 'some-button',
78 | onClick: () => alert('JS!'),
79 | },
80 | 'Hello 🎄'
81 | )
82 | ```
83 |
84 | ## Tinker with it
85 |
86 | Use the workspace below and play with the JSX.
87 |
88 | * Try using `class` instead of `className`. What error do you get?
89 | * Nest a couple elements inside of each other. Did they render as expected? How would you write the same using `React.createElement()`?
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/src/pages/2017/20.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/BlogPost.astro
3 | title: "Day 20: Components: What do they know? Do they know things?? Let's Find out!"
4 | date: "2017-12-20T12:00:00.000Z"
5 | ---
6 |
7 |
8 |
9 | [Smart vs. Dumb components](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0)
10 | is a dichotomy that has dominated the React conversation as long as React has
11 | existed.
12 |
13 | Here's the nut: **Some components know things. Some don't.**
14 |
15 | ## Knowing components
16 |
17 | [Yesterday's](/2017/19) Pokemon app only has **knowing** components. They know
18 | the `id` and how to change that `id`. They know when, where, and how to `fetch`
19 | new data.
20 |
21 | They know things.
22 |
23 | ## Unknowing components
24 |
25 | **Unknowing** components operate on `props` alone. If the component works
26 | strictly with `props`, it's an **unknowing** component.
27 |
28 | ```jsx
29 | const Unknowing = props => (
30 |
Hi {props.name}! I didn't know you until now.
31 | )
32 | ```
33 |
34 | ## Extracting unknowing components
35 |
36 | [Yesterday's](/2017/19) `Pokemon` is all tangled. It knows how to fetch **and**
37 | how to present.
38 |
39 | We can untangle it by splitting `Pokemon` into two components.
40 |
41 | `FetchPokemon` (**knowing**) keeps the smarts required to fetch a Pokemon then
42 | gives what it knows to `Pokemon` (**unknowing**) through props.
43 |
44 | ```jsx
45 | class FetchPokemon extends React.Component {
46 | state = { character: null }
47 | componentDidMount() { ... }
48 | componentWillReceiveProps(nextProps) { ... }
49 |
50 | render() { return ) }
51 | }
52 | ```
53 |
54 |
55 |
56 | `Pokemon` (**unknowing**) has no smarts and only renders what it's given.
57 |
58 | ```jsx
59 | const Pokemon = props =>
60 |
68 |
69 | This pattern alone is useless—strictly cosmetic.
70 | But—when paired with [render props](/2017/19)—it's how you do [separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns) in React.
71 |
72 | ## Tinker with it
73 |
74 | Use the workspace below and explore **knowing** and **unknowing** components.
75 |
76 | * Reconstruct the coupled version of `Pokemon`.
77 | * Separate `Pokemon` and `FetchPokemon` again. Practice makes perfect.
78 | * See the [render prop](2017/19) opportunity? Take it.
79 |
80 |
8 |
9 | ## Welcome to the (H)OC
10 |
11 | I'm gonna level with you, I don't know to explain higher-order components to you.
12 | I work in analogies and there just isn't one for HOCs.
13 |
14 | HOCs are like bacon-wrapped dates, where bacon is functions and dates are components, and bacon harvests dates for the wrapped dates to shove inside themselv...
15 |
16 | **WHAT DA?!**
17 |
18 | Yeah, no good analogies. [Read the docs](https://reactjs.org/docs/higher-order-components.html).
19 |
20 | ## The good news
21 |
22 | The good news is that most HOCs share a basic skeleton.
23 |
24 | Using our language from [yesterday](/2017/20),
25 | here's a HOC named `withKnowledge`.
26 |
27 |
30 |
31 |
32 |
33 | ```jsx
34 | function withKnowledge(UnkowingComponent) {
35 | class KnowingComponent extends React.Component {
36 | state = { knowledge: "Things I know" }
37 |
38 | render() {
39 | return (
40 |
44 | )
45 | }
46 | }
47 | }
48 | ```
49 |
50 |
51 | `withKnowleding` wraps our **knowing** component in a function that takes an **unknowing** component as an argument and **smooshes** them together.
52 |
53 | Bring your own "knowledge" and you know everything you need to about HOCs.
54 |
55 | ## Why though?
56 |
57 | Higher-order components are another way of [uncoupling](/2017/18) components.
58 | Many popular libraries use them.
59 |
60 | I think there are only a couple reasons to use them and you'll likely never run into one in regular app code.
61 |
62 |
63 | ## Tinker with it
64 |
65 | Explore the code below.
66 | I've used the higher-order component pattern to **uncouple** `FetchPokemon` from `Pokemon`.
67 | It's now `withPokemon()`.
68 |
69 | Can you change it to use a **render prop**?
70 | Which do you prefer?
71 |
72 |
8 |
9 | Our `withPokemon` HOC is mostly reusable. But it displays that static
10 | `loading...` message.
11 |
12 | Let's make that replaceable.
13 |
14 | ## Components over configuration
15 |
16 | The `defaultProps` API is one of my favorites. Use it to provide sensible
17 | defaults for your components.
18 |
19 | For `withPokemon`, we should always indicate that the component is doing work.
20 | But we should make make the message configurable.
21 |
22 | We know that props can be components. So lets put `
32 | }
33 | ```
34 |
35 |
36 |
37 | _(Yes, this works with component [functions](/2017/3) and [classes](/2017/5)
38 | alike.)_
39 |
40 | Now we update `render()` and anyone on the team can use any loading component
41 | they want.
42 |
43 |
,
67 | }
68 | }
69 | ```
70 |
71 |
72 |
73 | It reduces redundant typing but only for [class components](/2017/5).
74 |
75 | ## Tinker with it
76 |
77 | Use the workspace below and explore `defaultProps`.
78 |
79 | * Change `static defaultProps` to today's syntax and back again.
80 | * Change `renderLoading` to use a [render prop](/2017/18). What changes in
81 | `render()`?
82 | * Create a new [functional component](/2017/3) named `Loading` and use it in
83 | `defaultProps`. What changes in `render()`?
84 |
85 |
8 |
9 | `IdPager` knows too much. It knows how to manage an `id` **and** display buttons.
10 |
11 | ## Pager Duty
12 |
13 | Let's pass the actions into `this.props.render` with the `id`.
14 |
15 | I like putting them in an object.
16 | It lets me add and remove actions without impacting the [number of arguments](https://en.wikipedia.org/wiki/Arity).
17 |
18 |
32 |
33 |
34 |
35 | Now—for us—those button components move up to our root `ReactDOM.render()`.
36 |
37 | ## Design at will
38 |
39 | Now that `IdPager` exposes actions, the implementation is up to the developer using it. Instead of the default buttons we used, they can get creative!
40 |
41 |
54 |
55 | ## Tinker with it
56 |
57 | Use the workspace below and explore actions in [render props](/2017/19).
58 |
59 | * Add an action. Maybe a `Start over` button that goes back to `1`.
60 | * Show you colors and add some style!
61 |
62 |
8 |
9 | If you click any of the buttons in our app _really fast_, you'll see this error.
10 |
11 | 
12 |
13 | We call `setState` inside the asynchronous `fetch`.
14 | All works if our component is around to get updated but, when we click faster than the request can resolve, the component that requested it isn't around to be updated.
15 |
16 | Our app has put another component there.
17 |
18 | ## Clean up your shit, Todd!
19 |
20 | When we see this error, it means we did setup that we need to clean up.
21 | We do cleanup in the [componentWillUnmount](https://reactjs.org/docs/react-component.html#componentwillunmount) lifecycle method.
22 |
23 | In `FetchPokemon` component needs to `cancel` the [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) returned by [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).
24 |
25 | ## Maybe next year...
26 |
27 | I've updated the code below but cancellable `fetch` is a whole thing and I've got eggnog to drink.
28 |
29 | As always—the, the [React Docs](https://reactjs.org/) work for you all year long and there's a [great post on just this topic](https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html).
30 |
31 | Happy holidays and have a Merry Christmas!
32 |
33 | ⚛️🌲
34 |
35 | ❤️ chantastic
36 |
37 | ## Tinker with it
38 |
39 |
8 |
9 | ## Tinker with it
10 |
11 | You did great.
12 | I'm proud of you for sticking with it to the end.
13 |
14 | If you made it through, you have all the essential knowledge you need to be a great React developer.
15 | The rest is practice.
16 |
17 | Take it easy today.
18 | 2018 has great things in store for you.
19 | I'm excited to see what you make.
20 |
21 | 💖 @chantastic
22 |
23 |
8 |
9 | Components are just functions.
10 |
11 | 🤯
12 |
13 | ### How do I write said component functions?
14 | Easy.
15 |
16 | Here's one that spits out our `Hello 🎄` wherever used.
17 |
18 | ```jsx
19 | function Greeting() {
20 | return
Hello 🎄
;
21 | }
22 | ```
23 |
24 | ### How do I use said component functions?
25 |
26 | JSX has you covered.
27 | Just use the function name like an HTML tag.
28 |
29 | ```jsx
30 |
31 |
32 | ```
33 |
34 | ### That's it?
35 |
36 | Pretty much, but here's something to remember - Capitalize your Custom Components.
37 | If you don't, JSX transformers assume you meant a native DOM element.
38 |
39 | ## Tinker with it
40 |
41 | Use the workspace below to play with components.
42 |
43 | * Write and use a component of your own creation.
44 | * Mix custom components and native components. Any issues?
45 |
46 |
8 |
9 | If components are functions and functions take arguments,
10 | components should take arguments.
11 |
12 | They do!
13 |
14 | In React we call component arguments `props`.
15 |
16 | ## Where do props come from?
17 |
18 | Props are authored like HTML attributes.
19 | Say you want to add a `name` prop.
20 | Add it as an "attribute" where you use the component:
21 |
22 | ```jsx
23 |
24 | ```
25 |
26 | ## Now how do I use 'em *in* the component?
27 |
28 | React puts `props` in a single object.
29 | And that object is conveniently, the first argument of our component function.
30 |
31 | Once you have the `props` object, you can interpolate values in with `{}`.
32 |
33 | ```jsx
34 | function Greeting(props) {
35 | return
Hello {props.name}
;
36 | }
37 | ```
38 |
39 | ## Tinker with it
40 |
41 | Use the workspace below and play with props.
42 |
43 | Be creative and have fun!
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/pages/2017/5.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/BlogPost.astro
3 | title: "Day 5: Components can use classes for special powers"
4 | date: "2017-12-05T12:00:00.000Z"
5 | ---
6 |
7 |
8 |
9 | Some components have to be special.
10 | Those components get defined with **class**.
11 |
12 | ```jsx
13 | class ClapCounter extends React.Component {
14 | render() {
15 | return (
16 |
17 | 👏 be the first to clap
18 |
19 | );
20 | }
21 | }
22 | ```
23 |
24 | It's not much to look at now.
25 | We'll fill it in this week.
26 |
27 | ## Some ground rules
28 |
29 | Component classes extend `React.Component` and define a `render()` method.
30 |
31 | For comparison, here's what `Greeting` looks like as a component class.
32 |
33 | ```jsx
34 | class Greeting extends React.Component {
35 | render() {
36 | return (
37 |
Hello {this.props.name}.
38 | );
39 | }
40 | }
41 | ```
42 |
43 |
44 | ## What speshul powerz they got?!
45 |
46 | Unlike function components, class components have an instance—`this`. This gives us [lifecycle methods and state APIs](https://reactjs.org/docs/react-component.html) for some seriously cool interactivity.
47 |
48 | Sooooooo much ahead!
49 |
50 | ## Tinker with it
51 |
52 | Use the workspace below and play with component classes.
53 |
54 | * Convert `Greeting` to a component class and back to a function.
55 | * Define a new component using class. Be sure not to forget `extends`, `render()` and `this`.
56 |
57 |
8 |
9 | Look at HTML.
10 | It lets you handle DOM events inline.
11 |
12 | ```html
13 |
20 | ```
21 |
22 |
23 |
24 | I could tell the sordid history that landed this in the "bad practice" bucket but we'd both be bored.
25 |
26 | Suffice to say, folks bent on "good practices" had to jump through hoops to implement safe, reusable, cross-browser event handlers.
27 |
28 | React Events don't share these trade-offs.
29 |
30 | ## Adding event handlers in React
31 |
32 | Let's add an `onClick` (remember to camelCase) to our `ClapsCounter` from [yesterday](/2017/5).
33 |
34 | ```jsx
35 |
41 | ```
42 |
43 | ### Look, Ma! No strings!
44 |
45 | First, you'll notice that we're not using strings anymore 🙌 🙌 🙌
46 |
47 | This is a theme in React:
48 | **fewer strings, more JavaScript.**
49 |
50 | ### Look, Ma! No DOM handlers!
51 |
52 | What the fish?
53 | Where did our event handler go?
54 |
55 | 
56 |
57 | React did the work of making this "bad practice" a "good practice" by adding our event handler at the top of the `document`.
58 |
59 | This is another React theme:
60 | **best practices don't have to be complicated practices.**
61 |
62 | ### But really, what happened?
63 |
64 | Magic 🔮👻
65 |
66 | If you **must** know, you can read more about React's [Event handling magic](https://reactjs.org/docs/handling-events.html) and [Synthetic Events](https://reactjs.org/docs/events.html).
67 |
68 | ## Tinker with it
69 |
70 | Use the workspace below and play with events.
71 |
72 | - Add a few mouse events.
73 | - For kicks, add a text input. Anything weird happen? Like you can't type in it? Spooooooky.
74 |
75 |
8 |
9 | > Being sexy is all about attitude... It's a state of mind.
10 | — Amisha Patel
11 |
12 | One of the [special powers](/2017/5) of class components is their ability to hold state.
13 |
14 | With state, you get interactivity.
15 | No state, no interactivity.
16 | So component state isn't just **a** feature, it's **the** feature.
17 |
18 | ## How I do dat state hawtnez?
19 |
20 | Start with an initial state.
21 | Do this in the constructor of your class components.
22 |
23 | ```jsx
24 | class MyStateOfMind extends React.Component {
25 | constructor() {
26 | super();
27 | this.state = { sexy: true }
28 | }
29 | ...
30 | ```
31 |
32 | In `create-react-app` projects, use this [ESNext syntax](https://babeljs.io/docs/plugins/transform-class-properties/) to avoid the constructor noise.
33 |
34 | ```jsx
35 | class MyStateOfMind extends React.Component {
36 | state = { sexy: true }
37 | ...
38 | ```
39 |
40 | ## Back to Claps
41 |
42 | Let's add a `clapCount` state to the `ClapsCounter` we worked on [yesterday](/2017/6).
43 |
44 | ```jsx
45 | class ClapCounter extends React.Component {
46 | state = { clapCount: 0 }
47 |
48 | render() {
49 | return (
50 |
51 |
59 | be the first to clap
60 |
61 | );
62 | }
63 | }
64 | ```
65 |
66 | ## Stay sexy, nerds
67 |
68 | Now you know how to initialize state and your state of mind will always be sexy.
69 |
70 | As for our `clapCount` state, it'll be changing tomorrow...
71 |
72 | ## Tinker with it
73 |
74 | Use the workspace below and play with state.
75 | * Change the initial state from `0` to `100`. Does the alert read `101 claps`?
76 | * Add more state properties. Try strings, numbers, function expressions, whatever you want.
77 |
78 |
8 |
9 | Managing state is hard.
10 |
11 | I'll take four days to cover the React APIs for setting state.
12 | So don't read today's lesson without coming back for [set state dynamically](/2017/9) and [setState is a food truck](/2017/10).
13 |
14 | ## setState is GrrrrREAT!
15 | Meet [setState()](https://reactjs.org/docs/react-component.html#setstate).
16 |
17 | ```js
18 | this.setState({ someProp: newState })
19 | ```
20 |
21 |
22 | This is a [special power](/2017/5) our components get by extending `React.Component`.
23 | When called, `setState` updates the local `state` object and re-renders the component.
24 |
25 | ## Set state statically
26 | Continue [yesterday's](/2017/7) example and replace the `alert` with a proper state change.
27 |
28 | ```js
29 |
38 | ```
39 |
40 | ## Limitations
41 |
42 | Above, we call `setState()` with a new state object.
43 |
44 | There are [two ways to use setState](https://reactjs.org/docs/react-component.html#setstate).
45 | This one is easy to understand but quickly limiting.
46 | We set `clapCount` with a static value but how do we use a dynamic value?
47 | How do we keep our counter counting, transitioning current state to the next state?
48 |
49 | Tomorrow we'll learn how to transition state.
50 |
51 | ## Tinker with it
52 |
53 | Use the workspace below and set some state.
54 | * Change value you set `clapCount` to. Get crazy; try a string.
55 | * Create another component that counts something else. 👍s, 🙌s, anything!
56 | * Keep the counter counting. Try your hand at making state changes dynamic.
57 |
58 |
8 |
9 | If you want to set state dynamically, use a **function**.
10 |
11 | ```js
12 | this.setState(function(previousState) {
13 | return { someProp: previousState.someProp + 1 }
14 | })
15 | ```
16 |
17 |
18 | We give `setState` an anonymous function to be called with `state`.
19 | Our function takes that `state` and returns a new object with new values derived from the old.
20 |
21 | ## Concise but not clear
22 |
23 | This is how I write `setState(fn)` in a modern code base.
24 | It's how you're likely to see it in the real world.
25 |
26 | ```js
27 | this.setState((previousState) =>
28 | ({ clapCount: previousState.clapCount + 1 })
29 | )
30 | ```
31 |
32 |
33 | [Arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) have implicit returns
34 | but if the return type is an object, you must wrap it in parentheses.
35 |
36 | ## Why `previousState` not `currentState`?
37 |
38 | While `setState` does update state—**eventually**—it does so asynchronously and in batches.
39 |
40 | Because of that implementation detail, the state that your function receives might not be the current state.
41 |
42 | ## I'm so confused...
43 |
44 | Yeah.
45 | It's very confusing.
46 |
47 | Tomorrow let's implement our own state setter.
48 | You'll get a better idea of how `setState` sausage is made.
49 |
50 | _(I'll use an actual sausage to illustrate)_
51 |
52 | ## Tinker with it
53 |
54 | Use the workspace below and set some state with functions.
55 | * Experiment with syntax. Use both [function declarations](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function) and [arrow function expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) to dynamically set state. Does one seem clearer than the other?
56 | * For fun, use [destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) to unpack values from the `state` object.
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/src/pages/2017/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import BaseHead from "../../components/BaseHead.astro";
3 | import BlogHeader from "../../components/BlogHeader.astro";
4 | import BlogPostPreview from "../../components/BlogPostPreview.astro";
5 |
6 | let title = "React Holiday";
7 | let description = "An annual celebration of React.";
8 | let permalink = "https://react.holiday/";
9 |
10 | let allPosts = await Astro.glob("./*.md");
11 | allPosts = allPosts.sort(
12 | (a, b) =>
13 | new Date(a.frontmatter.date).valueOf() -
14 | new Date(b.frontmatter.date).valueOf()
15 | );
16 | ---
17 |
18 |
19 |
20 |
25 |
26 |
27 |
61 |
66 |
67 |
68 |
69 |
70 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/pages/2020/1.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/BlogPost.astro
3 | title: "Welcome to React Holiday 2020!"
4 | date: "2020-12-01T12:00:00.000Z"
5 | ---
6 |
7 | Hey friends 👋
8 |
9 | It’s been a year since we last talked — a wild, unbelievable year!
10 |
11 | A lot happens in a year and you might not want 25 React-related emails. No problem. I'm grateful for the times we shared in previous years and encourage you to unsubscribe using the clearly named button below.
12 |
13 | Ok! Let’s talk about the season ahead!
14 |
15 | ## Everything but React
16 |
17 | The developers I admire most have a command over all the tools in their proverbial toolbelt.
18 | React might be their favorite hammer but when they need to drive a screw or saw thru a post, they use different tools.
19 |
20 | As web developers, the tools of our trade are JavaScript, JSX, HTML, and CSS.
21 |
22 | React is so incredible that we it often favor it, even when it’s not the best tool.
23 |
24 | This React Holiday, we’ll cover 23 practices in JavaScript, JSX, and HTML that support and enhance your professional React development.
25 |
26 | ## First, A Question
27 |
28 | Our first few lessons go deep on a JavaScript primitive type that is favored in React.
29 |
30 | Every UI framework favors a primitive type. For many that’s the String type. Others rely heavily on configuration Objects.
31 |
32 | What do you think the most privileged type in React is?
33 |
--------------------------------------------------------------------------------
/src/pages/2020/10.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/BlogPost.astro
3 | title: "JSX Dynamics"
4 | date: "2020-12-10T12:00:00.000Z"
5 | ---
6 |
7 | There’s a simple heuristic that JSX uses to determine what you’re trying to render.
8 |
9 | Lowercase `` becomes `React.createElement("div")`. A string is used to create a host element (react-dom) by that name.
10 |
11 | Uppercase `` becomes `React.createElement(MyDiv)`. A function reference is used to create an element from a named component definition.
12 |
13 | Object property `` becomes `React.createElement(Module.Component)`. A function reference is used to create an element from a component definition, nested inside an object. (It also works with lowercase `props.componentName`. Give it a try!)
14 |
15 | But you can do more without JSX than you can with it.
16 |
17 | For examples, there’s no JSX equivalent for a conditional: `React.createElement(someCondition ? FancyDiv : "div")`
18 |
19 | ## Take it home
20 |
21 | How do you handle dynamic element creation?
22 |
--------------------------------------------------------------------------------
/src/pages/2020/11.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/BlogPost.astro
3 | title: "Going The Way of The Render Prop"
4 | date: "2020-12-11T12:00:00.000Z"
5 | ---
6 |
7 | Removing JSX from components, a couple confusing patterns become clearer.
8 |
9 | If you didn’t already hate JSX for it’s uses of className and htmlFor over class and html, you hopped on the hate-train with [render props](https://reactpatterns.com/#render-prop).
10 |
11 | ## WTF is a render prop?
12 |
13 | The render prop pattern is the [delegation pattern](https://en.wikipedia.org/wiki/Delegation_pattern), branded for React. It extends a component’s children to take a function — which it calls back with data.
14 |
15 | In use, render props look like this:
16 |
17 | `{width =>
{width}
}`
18 |
19 | That looks nothing like the HTML-like syntax I was promised! So let’s check it out without JSX:
20 |
21 | `createElement(WindowWidth, null, width =>
{width}
)`
22 |
23 | With JS removed, this is clearly a box-standard callback.
24 |
25 | ## Where did all the render props go?
26 |
27 | For the most part, render props have been replaced by [Hooks](https://reactjs.org/docs/hooks-intro.html). However, they live on in legacy codebases, the Context.Consumer API, and in listing components (which we’ll cover next).
28 |
29 | ## Take it home
30 |
31 | [This CodeSandbox](https://codesandbox.io/s/relaxed-dew-uq3fq?file=/src/App.js) uses a JSX render prop to fetch a Pokemon. Take a moment and remove the JSX. Which do you find more scrutable and why?
32 |
--------------------------------------------------------------------------------
/src/pages/2020/12.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/BlogPost.astro
3 | title: "Use Render Props for Customizable Lists"
4 | date: "2020-12-12T12:00:00.000Z"
5 | ---
6 |
7 | Before [render props](https://reactpatterns.com/#render-prop) where used to stitch stateful and non-stateful components together, they were used in React Native for [rendering lists](https://reactnative.dev/docs/flatlist).
8 |
9 | This pattern borrows from the iOS notion of delegation. And remember, “render prop” == “React-branded delegation”. Here’s what that looks like to in React Native:
10 |
11 | ```jsx
12 | {item}} />
13 | ```
14 |
15 | This component takes data as a prop and a iterator callback to map over it with. A simplified implementation looks like this:
16 |
17 | ```jsx
18 | function FlatList({ data, renderItem }) {
19 | return <>{data.map(renderItem)}>;
20 | }
21 | ```
22 |
23 | By giving the component consumer control of both the input and output, we've made this List component generic and reusable.
24 |
25 | ## Take it home
26 |
27 | In [this CodeSandbox](https://codesandbox.io/s/nostalgic-hooks-m5c03?file=/src/App.js) you’ll find a `PokemonList` component that fetches a list of Pokemon and exposes them via render prop. Extract the rendered list into a generic `List` component. Remember, that component should take both _data_ and the _iterator_ callback needed to transform it.
28 |
--------------------------------------------------------------------------------
/src/pages/2020/13.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/BlogPost.astro
3 | title: "Inject Components"
4 | date: "2020-12-13T12:00:00.000Z"
5 | ---
6 |
7 | Below is the first example on [reacts.org](https://reactjs.org/). It shows the interplay of functions, JavaScript, JSX, and HTML that makes React unique.
8 |
9 | ```jsx
10 | let Greeting({ name }) { return
Hello {name}
}
11 | ```
12 |
13 | It also demonstrates a big omission in the design of JSX.
14 |
15 | JSX doesn’t have a syntax for rendering custom components with an alternate host element. Specially, this component will always render as a `div` — excluding it from [inline](https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements) use.
16 |
17 | It’d be nice to tell React “render Greeting but as a span.”
18 |
19 | There’s no first class JSX syntax for that. But React, JSX, and a bit of JS trickery make this possible in our own code. Use what we’ve learned about JS expressions to _inject_ the desired component by passing it in as a prop.
20 |
21 | ```jsx
22 |
23 | ```
24 |
25 | Of course custom components can be injected as well.
26 |
27 | ```jsx
28 |
29 | ```
30 |
31 | Here’s what this pattern looks like as a component declaration:
32 |
33 | ```jsx
34 | let Greeting({ As, name }) {
35 | return Hello {name}
36 | }
37 | ```
38 |
39 | ## Take it Home
40 |
41 | There’s something kinda funny about this `As` prop we’ve made. That funny thing is because of a JSX heuristic we learned about earlier. Can you put your finger on it? Can you change it to make it more natural? [Explore in this CodeSandbox](https://codesandbox.io/s/as-prop-step-1-j7ep3?file=/src/App.js).
42 |
--------------------------------------------------------------------------------
/src/pages/2020/14.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/BlogPost.astro
3 | title: "Reassign Destructed Values"
4 | date: "2020-12-14T12:00:00.000Z"
5 | ---
6 |
7 | Our component ended up in a weird place yesterday.
8 |
9 | ```jsx
10 | let Greeting({ As, name }) {
11 | return Hello {name}
12 | }
13 | ```
14 |
15 | The capitalized `As` prop stands out. The capitalization is important to make the JSX transformer evaluate `As` as an expression. However, the capitalized attribute looks strong when used:
16 |
17 | Fortunately, JavaScript has a [destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) syntax that allows us to do two things at once:
18 |
19 | - receive as, as a lowercase prop
20 | - assign as's [value to a new `As` variable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Assigning_to_new_variable_names), capitalized for JSX evaluation
21 |
22 | Using a colon — where we unpack props — the new assignment looks like this: `{ as: As }`
23 |
24 | Here it is in context of our component declaration:
25 |
26 | ```jsx
27 | function Greeting({ as: As, name }) {
28 | return Hello {name};
29 | }
30 | ```
31 |
32 | ## Take it home
33 |
34 | When we assign object properties to new variable names, we can name them whatever we want. [Open this CodeSandbox](https://codesandbox.io/s/as-prop-step-2-ks36s?file=/src/App.js) and toy with the re-assignment syntax. Try Component, Tag, or anything else you like. This is a local variable. So there’s no “wrong” way to do it.
35 | While you’re there, what happens if we don’t supply an as prop? Where can we provide a sensible default?
36 |
--------------------------------------------------------------------------------
/src/pages/2020/15.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/BlogPost.astro
3 | title: "Undefined is not a Default"
4 | date: "2020-12-15T12:00:00.000Z"
5 | ---
6 |
7 | I love seeing React’s continued progress toward standard JavaScript.
8 |
9 | We went from `createClass` to class in 2014. Then from class to function in 2018. Every major change made a bigger and bigger bet on bone-stock JavaScript.
10 |
11 | One API we needed for `createClass` class components was `defaultProps`. It let us use an appropriate fallback where a prop was required but not provided. This API made props available to all of the many lifecycle events.
12 |
13 | Now — with Hooks — “lifecycle” functions happen inside the bodies of component functions. So we can lean on standard JavaScript to replace this API.
14 |
15 | ## Undefined is not default
16 |
17 | In our last lesson, we reassigned as (lowercase) to `As` (uppercase) — when unpacking our props with destructuring assignment.
18 |
19 | ```js
20 | function Greeting({ as: As, name }) { … }
21 | ```
22 |
23 | Unfortunately this component has a bug. What happens if we try to render it without providing the as prop? It throws an error; it can’t render undefined as a component.
24 |
25 | Fortunately, we can declare a default when destructuring props:
26 |
27 | ```js
28 | function Greeting({ as: As = “div”, name }) { … }
29 | ```
30 |
31 | ## Take it home
32 |
33 | Take a minute to change the defaults and explore overriding them in [this CodeSandbox](https://codesandbox.io/s/as-prop-step-3-fbo7y?file=/src/App.js).
34 |
35 | Take it further by asking: is there a way in React that we could render this without any surrounding element? Hint: the answer has to do with what we’ve learned about arrays and React.
36 |
--------------------------------------------------------------------------------
/src/pages/2020/16.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/BlogPost.astro
3 | title: "Make Components Arrays"
4 | date: "2020-12-16T12:00:00.000Z"
5 | ---
6 |
7 | Arrays are special in React.
8 | I know, I know. I'm beating a dead horse with this array thing. But did you know that components can return arrays too?
9 |
10 | ```jsx
11 | function MyComponentReturnsAnArray() {
12 | return ["Let's", GO!!!];
13 | }
14 | ```
15 |
16 | It looks weird but it's totally valid.
17 |
18 | Returning arrays from components is such a valuable pattern that React has a tool for expressing arrays with JSX. It's the [React.Fragment](https://reactjs.org/docs/fragments.html#gatsby-focus-wrapper) component. And it's entire job is to return a JSX-expressed array:
19 |
20 | ```jsx
21 | function MyComponentReturnsAnArray() {
22 | return (
23 |
24 | Let's GO!!!
25 |
26 | );
27 | }
28 | ```
29 |
30 | ## Take it Home
31 |
32 | Take [yesterday's CodaSandbox](https://codesandbox.io/s/as-prop-step-3-fbo7y) and update the as prop default to a React Fragment. Be sure to inspect the results in the DevTools. No added DOM elements!
33 |
--------------------------------------------------------------------------------
/src/pages/2020/17.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/BlogPost.astro
3 | title: "Trust the Prop-cess"
4 | date: "2020-12-17T12:00:00.000Z"
5 | ---
6 |
7 | The estute reader is worrying about props right now. Prop-handling is a crucial part of component design that I've conveniently left it out.
8 |
9 | For simple components like our Greeting, it's common to take the [rest of the props](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Assigning_the_rest_of_an_array_to_a_variable) and apply them to the returned element.
10 |
11 | ```jsx
12 | function Greeting({ as: As = React.Fragment, name, ...props }) {
13 | return Hello {name};
14 | }
15 | ```
16 |
17 | This ensures native element attributes like className, id, and aria-label get "forwarded" to the returned element.
18 |
19 | But what happens when we provide className to our default Fragment and there is no element? I'm glad you asked…
20 |
21 | 
22 |
23 | React has terrific errors. This one teaches us that Fragment — when used as our root — can only take key and children as props.
24 |
25 | ## Take it home
26 |
27 | There are two ways to resolve this warning. I'm curious which one you reach for. Fork [this week's CodeSandbox](https://codesandbox.io/s/as-prop-step-4-poovg?file=/src/App.js) and reply with your solution. Or [join our discussion in Discord](https://discord.gg/nVrhSZwbvE) to see how others solved it!
28 |
--------------------------------------------------------------------------------
/src/pages/2020/18.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/BlogPost.astro
3 | title: "Components vs Competence"
4 | date: "2020-12-18T12:00:00.000Z"
5 | ---
6 |
7 | It's taken 5 unique concepts to make a Greeting component behave nearly as transparently as an HTML element. I'm starting to see why folks say React is hard.
8 |
9 | So I have to ask:
10 | Is the work we did with Greeting — the simplest component in the React docs — valuable?
11 |
12 | No, it isn't.
13 |
14 | These two lines would be clearer:
15 |
16 | ```jsx
17 | let greet = (name) => `Hello ${name}.`;
18 | {greet("chantastic")};
19 | ```
20 |
21 | The solution is more composable. It uses fewer lines. And we don't need to know about component injection, destructured prop reassignment, component-array switching, capturing and spreading host element attributes, className munging, or clobbering the children prop (which we hadn't even addressed yet)…
22 |
23 | We simply use a function and a regular HTML element.
24 |
25 | Novel!
26 |
27 | ## Take it Home
28 |
29 | This lesson might feel like a trick. It's not.
30 | Most of the clever things we do in React might be better expressed as a JavaScript function and common HTML element.
31 |
32 | Don't stack clever feature atop clever feature just to re-create what already exists. Ask yourself if the task at hand needs a component at all. You might be surprised to find that it doesn't.
33 |
34 | Do you have a component that causes harm instead of creating value? Hit reply and let me know.
35 |
--------------------------------------------------------------------------------
/src/pages/2020/19.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/BlogPost.astro
3 | title: "So, What is React Anyway?"
4 | date: "2020-12-19T12:00:00.000Z"
5 | ---
6 |
7 | Now that we're thinking outside the component, let's talk about [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML).
8 |
9 | [JSX](https://reactjs.org/docs/introducing-jsx.html) and HTML are not the same thing but they are siblings.
10 | React (on the web) takes JSX descriptors and renders them as HTML elements.
11 |
12 | HTML is an initialism for HyperText Markup Language. It's a scripting language baked into every web browser — designed to make the web navigable and interactive.
13 |
14 | The cornerstone element of HTML is `` (anchor) an element that connects one web document to another with a click or tap. Additional elements like `