3 |
4 | Learn the foundational concepts necessary for building
5 | React applications and libraries
6 |
7 |
8 | Learn everything you need to be effective with the fundamental building
9 | block of React applications. When you're finished, you'll be prepared to
10 | create React components to build excellent experiences for your app's users.
11 |
20 |
21 |
22 |
23 |
24 | [![Build Status][build-badge]][build]
25 | [![GPL 3.0 License][license-badge]][license]
26 | [![All Contributors][all-contributors-badge]](#contributors-)
27 | [![Code of Conduct][coc-badge]][coc]
28 | [![Gitpod ready-to-code][gitpod-badge]](https://gitpod.io/#https://github.com/kentcdodds/react-fundamentals)
29 |
30 |
31 | ## Prerequisites
32 |
33 | - Read through
34 | ["JavaScript to Know for React"](https://kentcdodds.com/blog/javascript-to-know-for-react)
35 | - Install the React DevTools
36 | ([Chrome](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en)
37 | (recommended),
38 | [Firefox](https://addons.mozilla.org/en-US/firefox/addon/react-devtools/))
39 |
40 | > NOTE: The EpicReact.dev videos were recorded with React version ^16.13 and all
41 | > material in this repo has been updated to React version ^18. Differences are
42 | > minor and any relevant differences are noted in the instructions.
43 |
44 | ## Quick start
45 |
46 | It's recommended you run everything in the same environment you work in every
47 | day, but if you don't want to set up the repository locally, you can get started
48 | in one click with [Gitpod](https://gitpod.io),
49 | [CodeSandbox](https://codesandbox.io/s/github/kentcdodds/react-fundamentals), or
50 | by following the [video demo](https://www.youtube.com/watch?v=gCoVJm3hGk4)
51 | instructions for [GitHub Codespaces](https://github.com/features/codespaces).
52 |
53 | [](https://gitpod.io/#https://github.com/kentcdodds/react-fundamentals)
54 |
55 | For a local development environment, follow the instructions below
56 |
57 | ## System Requirements
58 |
59 | - [git][git] v2.13 or greater
60 | - [NodeJS][node] `14 || 16 || 18`
61 | - [npm][npm] v8.16.0 or greater
62 |
63 | All of these must be available in your `PATH`. To verify things are set up
64 | properly, you can run this:
65 |
66 | ```shell
67 | git --version
68 | node --version
69 | npm --version
70 | ```
71 |
72 | If you have trouble with any of these, learn more about the PATH environment
73 | variable and how to fix it here for [windows][win-path] or
74 | [mac/linux][mac-path].
75 |
76 | ## Setup
77 |
78 | > If you want to commit and push your work as you go, you'll want to
79 | > [fork](https://docs.github.com/en/free-pro-team@latest/github/getting-started-with-github/fork-a-repo)
80 | > first and then clone your fork rather than this repo directly.
81 |
82 | After you've made sure to have the correct things (and versions) installed, you
83 | should be able to just run a few commands to get set up:
84 |
85 | ```shell
86 | git clone https://github.com/kentcdodds/react-fundamentals.git
87 | cd react-fundamentals
88 | node setup
89 | ```
90 |
91 | This may take a few minutes. **It will ask you for your email.** This is
92 | optional and just automatically adds your email to the links in the project to
93 | make filling out some forms easier.
94 |
95 | A few common issues during `node setup` have involved PATH variables (above
96 | links or [here](https://github.com/kentcdodds/react-fundamentals/issues/27)),
97 | reinstalling git, node, or npm, and clearing npm caches.
98 |
99 | If you get any errors, please read through them and see if you can find out what
100 | the problem is. If you can't work it out on your own then please [file an
101 | issue][issue] and provide _all_ the output from the commands you ran (even if
102 | it's a lot).
103 |
104 | If you can't get the setup script to work, then just make sure you have the
105 | right versions of the requirements listed above, and run the following commands:
106 |
107 | ```shell
108 | npm install
109 | npm run validate
110 | ```
111 |
112 | If you are still unable to fix issues and you know how to use Docker 🐳 you can
113 | setup the project with the following command:
114 |
115 | ```shell
116 | docker-compose up
117 | ```
118 |
119 | ## Running the app
120 |
121 | To get the app up and running (and really see if it worked), run:
122 |
123 | ```shell
124 | npm start
125 | ```
126 |
127 | This should start up your browser. If you're familiar, this is a standard
128 | [react-scripts](https://create-react-app.dev/) application.
129 |
130 | You can also open
131 | [the deployment of the app on Netlify](https://react-fundamentals.netlify.app/).
132 |
133 | ## Running the tests
134 |
135 | ```shell
136 | npm test
137 | ```
138 |
139 | This will start [Jest](https://jestjs.io/) in watch mode. Read the output and
140 | play around with it. The tests are there to help you reach the final version,
141 | however _sometimes_ you can accomplish the task and the tests still fail if you
142 | implement things differently than I do in my solution, so don't look to them as
143 | a complete authority.
144 |
145 | ### Exercises
146 |
147 | - `src/exercise/00.md`: Background, Exercise Instructions, Extra Credit
148 | - `src/exercise/00.js`: Exercise with Emoji helpers
149 | - `src/__tests__/00.js`: Tests
150 | - `src/final/00.js`: Final version
151 | - `src/final/00.extra-0.js`: Final version of extra credit
152 |
153 | The purpose of the exercise is **not** for you to work through all the material.
154 | It's intended to get your brain thinking about the right questions to ask me as
155 | _I_ walk through the material.
156 |
157 | ### Helpful Emoji 🐨 💰 💯 📝 🦉 📜 💣 💪 🏁 👨💼 🚨
158 |
159 | Each exercise has comments in it to help you get through the exercise. These fun
160 | emoji characters are here to help you.
161 |
162 | - **Kody the Koala** 🐨 will tell you when there's something specific you should
163 | do
164 | - **Marty the Money Bag** 💰 will give you specific tips (and sometimes code)
165 | along the way
166 | - **Hannah the Hundred** 💯 will give you extra challenges you can do if you
167 | finish the exercises early.
168 | - **Nancy the Notepad** 📝 will encourage you to take notes on what you're
169 | learning
170 | - **Olivia the Owl** 🦉 will give you useful tidbits/best practice notes and a
171 | link for elaboration and feedback.
172 | - **Dominic the Document** 📜 will give you links to useful documentation
173 | - **Berry the Bomb** 💣 will be hanging around anywhere you need to blow stuff
174 | up (delete code)
175 | - **Matthew the Muscle** 💪 will indicate that you're working with an exercise
176 | - **Chuck the Checkered Flag** 🏁 will indicate that you're working with a final
177 | - **Peter the Product Manager** 👨💼 helps us know what our users want
178 | - **Alfred the Alert** 🚨 will occasionally show up in the test failures with
179 | potential explanations for why the tests are failing.
180 |
181 | ## Contributors
182 |
183 | Thanks goes to these wonderful people
184 | ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):
185 |
186 |
187 |
188 |
189 |
16 |
17 |
18 | ```
19 |
20 | The browser takes this HTML code and generates
21 | [the DOM (the Document Object Model)](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction)
22 | out of it. The browser then exposes the DOM to JavaScript so you can interact
23 | with it to add a layer of interactivity to your web-page.
24 |
25 | ```html
26 |
27 |
28 |
Hello World
29 |
32 |
33 |
34 | ```
35 |
36 | Years ago, people were generating HTML on the server and then adding JavaScript
37 | on top of that generated HTML for interactivity. However, as requirements for
38 | that interactivity became more challenging, this approach produced applications
39 | that were difficult to maintain and had performance issues.
40 |
41 | So modern JavaScript frameworks were created to address some of the challenges
42 | by programmatically creating the DOM rather than defining it in hand-written
43 | HTML.
44 |
45 | ## Exercise
46 |
47 | Production deploys:
48 |
49 | - [Exercise](http://react-fundamentals.netlify.app/isolated/exercise/01.html)
50 | - [Final](http://react-fundamentals.netlify.app/isolated/final/01.html)
51 |
52 | It's important to have a basic understanding of how to generate and interact
53 | with DOM nodes using JavaScript because it will help you understand how React
54 | works under the hood a little better. So in this exercise we're actually not
55 | going to use React at all. Instead we're going to use JavaScript to create a
56 | `div` DOM node with the text "Hello World" and insert that DOM node into the
57 | document.
58 |
59 | ## Extra Credit
60 |
61 | ### 1. 💯 generate the root node
62 |
63 | [Production deploy](http://react-fundamentals.netlify.app/isolated/final/01.extra-1.html)
64 |
65 | Rather than having the `root` node in the HTML, see if you can create that one
66 | using JavaScript as well.
67 |
68 | ## 🦉 Feedback
69 |
70 | Fill out
71 | [the feedback form](https://ws.kcd.im/?ws=React%20Fundamentals%20%E2%9A%9B&e=01%3A%20Basic%20JavaScript-rendered%20Hello%20World&em=).
72 |
--------------------------------------------------------------------------------
/src/exercise/02.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
29 |
30 |
--------------------------------------------------------------------------------
/src/exercise/02.md:
--------------------------------------------------------------------------------
1 | # Intro to raw React APIs
2 |
3 | ## 📝 Your Notes
4 |
5 | Elaborate on your learnings here in `src/exercise/02.md`
6 |
7 | ## Background
8 |
9 | React is the most widely used frontend framework in the world and it's using the
10 | same APIs that you're using when it creates DOM nodes.
11 |
12 | > In fact,
13 | > [here's where that happens in the React source code](https://github.com/facebook/react/blob/48907797294340b6d5d8fecfbcf97edf0691888d/packages/react-dom/src/client/ReactDOMComponent.js#L416)
14 | > at the time of this writing.
15 |
16 | React abstracts away the imperative browser API from you to give you a much more
17 | declarative API to work with.
18 |
19 | > Learn more about the difference between those two concepts here:
20 | > [Imperative vs Declarative Programming](https://tylermcginnis.com/imperative-vs-declarative-programming/)
21 |
22 | One important thing to know about React is that it supports multiple platforms
23 | (for example, native and web). Each of these platforms has its own code
24 | necessary for interacting with that platform, and then there's shared code
25 | between the platforms.
26 |
27 | With that in mind, you need two JavaScript files to write React applications for
28 | the web:
29 |
30 | - React: responsible for creating React elements (kinda like
31 | `document.createElement()`)
32 | - ReactDOM: responsible for rendering React elements to the DOM (kinda like
33 | `rootElement.append()`)
34 |
35 | ## Exercise
36 |
37 | Production deploys:
38 |
39 | - [Exercise](http://react-fundamentals.netlify.app/isolated/exercise/02.html)
40 | - [Final](http://react-fundamentals.netlify.app/isolated/final/02.html)
41 |
42 | Let's convert this to use React! But don't worry, we won't be doing any JSX just
43 | yet... You're going to use raw React APIs here.
44 |
45 | In modern applications you'll get React and React DOM files from a "package
46 | registry" like [npm](https://npmjs.com) ([react](https://npm.im/react) and
47 | [react-dom](https://npm.im/react-dom)). But for these first exercises, we'll use
48 | the script files which are available on [unpkg.com](https://unpkg.com) and
49 | regular script tags so you don't have to bother installing them. So in the
50 | exercise you'll be required to add script tags for these files.
51 |
52 | Once you include the script tags, you'll have two new global variables to use:
53 | `React` and `ReactDOM`.
54 |
55 | Here's a simple example of the API:
56 |
57 | ```javascript
58 | const elementProps = {id: 'element-id', children: 'Hello world!'}
59 | const elementType = 'h1'
60 | const reactElement = React.createElement(elementType, elementProps)
61 | const root = ReactDOM.createRoot(rootElement)
62 | root.render(reactElement)
63 | ```
64 |
65 | > 🦉 NOTE: prior to React v18, the API was: `ReactDOM.render` and that's what
66 | > you'll see in the EpicReact.dev videos. This material has been updated, so
67 | > you'll want to use the new `ReactDOM.createRoot` API as demonstrated above.
68 |
69 | Alright! Let's do this!
70 |
71 | ## Extra Credit
72 |
73 | ### 1. 💯 nesting elements
74 |
75 | [Production deploy](http://react-fundamentals.netlify.app/isolated/final/02.extra-1.html)
76 |
77 | See if you can figure out how to write the JavaScript + React code to generate
78 | this DOM output:
79 |
80 | ```html
81 |
82 |
83 |
84 | Hello
85 | World
86 |
87 |
88 |
89 | ```
90 |
91 | ## 🦉 Feedback
92 |
93 | Fill out
94 | [the feedback form](https://ws.kcd.im/?ws=React%20Fundamentals%20%E2%9A%9B&e=02%3A%20Intro%20to%20raw%20React%20APIs&em=).
95 |
--------------------------------------------------------------------------------
/src/exercise/03.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
32 |
33 |
--------------------------------------------------------------------------------
/src/exercise/03.md:
--------------------------------------------------------------------------------
1 | # Using JSX
2 |
3 | ## 📝 Your Notes
4 |
5 | Elaborate on your learnings here in `src/exercise/03.md`
6 |
7 | ## Background
8 |
9 | JSX is more intuitive than the raw React API and is easier to understand when
10 | reading the code. It's fairly simple HTML-like syntactic sugar on top of the raw
11 | React APIs:
12 |
13 | ```jsx
14 | const ui =
Hey there
15 |
16 | // ↓ ↓ ↓ ↓ compiles to ↓ ↓ ↓ ↓
17 |
18 | const ui = React.createElement('h1', {id: 'greeting', children: 'Hey there'})
19 | ```
20 |
21 | Because JSX is not actually JavaScript, you have to convert it using something
22 | called a code compiler. [Babel](https://babeljs.io) is one such tool.
23 |
24 | 🦉 Pro tip: If you'd like to see how JSX gets compiled to JavaScript,
25 | [check out the online babel REPL here](https://babeljs.io/repl#?builtIns=App&code_lz=MYewdgzgLgBArgSxgXhgHgCYIG4D40QAOAhmLgBICmANtSGgPRGm7rNkDqIATtRo-3wMseAFBA&presets=react&prettier=true).
26 |
27 | If you can train your brain to look at JSX and see the compiled version of that
28 | code, you'll be MUCH more effective at reading and using it! I strongly
29 | recommend you give this some intentional practice.
30 |
31 | ## Exercise
32 |
33 | Production deploys:
34 |
35 | - [Exercise](http://react-fundamentals.netlify.app/isolated/exercise/03.html)
36 | - [Final](http://react-fundamentals.netlify.app/isolated/final/03.html)
37 |
38 | Normally you'll compile all of your code at build-time before you ship your
39 | application to the browser, but because Babel is written in JavaScript we can
40 | actually run it _in_ the browser to compile our code on the fly and that's what
41 | we'll do in this exercise.
42 |
43 | So we'll include a script tag for Babel, then we'll update our own script tag to
44 | tell Babel to compile it for us on the fly. When you're done, you should notice
45 | the compiled version of the code appears in the `` of the DOM (which you
46 | can inspect using DevTools).
47 |
48 | ## Extra Credit
49 |
50 | ### 1. 💯 interpolate className and children
51 |
52 | [Production deploy](http://react-fundamentals.netlify.app/isolated/final/03.extra-1.html)
53 |
54 | "Interpolation" is defined as "the insertion of something of a different nature
55 | into something else."
56 |
57 | Let's take template literals for example:
58 |
59 | ```javascript
60 | const greeting = 'Sup'
61 | const subject = 'World'
62 | const message = `${greeting} ${subject}`
63 | ```
64 |
65 | See if you can figure out how to extract the `className` (`"container"`) and
66 | `children` (`"Hello World"`) to variables and interpolate them in the JSX.
67 |
68 | ```jsx
69 | const className = 'container'
70 | const children = 'Hello World'
71 | const element =
how do I make this work?
72 | ```
73 |
74 | 📜 The react docs for JSX are pretty good:
75 | [https://reactjs.org/docs/introducing-jsx.html](https://reactjs.org/docs/introducing-jsx.html)
76 |
77 | Here are a few sections of particular interest for this extra credit:
78 |
79 | - [https://reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-jsx](https://reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-jsx)
80 | - [https://reactjs.org/docs/introducing-jsx.html#specifying-attributes-with-jsx](https://reactjs.org/docs/introducing-jsx.html#specifying-attributes-with-jsx)
81 |
82 | ### 2. 💯 spread props
83 |
84 | [Production deploy](http://react-fundamentals.netlify.app/isolated/final/03.extra-2.html)
85 |
86 | What if I have an object of props that I want applied to the `div` like this:
87 |
88 | ```jsx
89 | const children = 'Hello World'
90 | const className = 'container'
91 | const props = {children, className}
92 | const element = // how do I apply props to this div?
93 | ```
94 |
95 | If we were doing raw React APIs it would be:
96 |
97 | ```jsx
98 | const element = React.createElement('div', props)
99 | ```
100 |
101 | Or, it could be written like this:
102 |
103 | ```jsx
104 | const element = React.createElement('div', {...props})
105 | ```
106 |
107 | See if you can figure out how to make that work with JSX.
108 |
109 | 📜 [https://reactjs.org/docs/jsx-in-depth.html#spread-attributes](https://reactjs.org/docs/jsx-in-depth.html#spread-attributes)
110 |
111 | ## 🦉 Feedback
112 |
113 | Fill out
114 | [the feedback form](https://ws.kcd.im/?ws=React%20Fundamentals%20%E2%9A%9B&e=03%3A%20Using%20JSX&em=).
115 |
--------------------------------------------------------------------------------
/src/exercise/04.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
24 |
25 |
--------------------------------------------------------------------------------
/src/exercise/04.md:
--------------------------------------------------------------------------------
1 | # Creating custom components
2 |
3 | ## 📝 Your Notes
4 |
5 | Elaborate on your learnings here in `src/exercise/04.md`
6 |
7 | ## Background
8 |
9 | Just like in regular JavaScript, you often want to share code which you do using
10 | functions. If you want to share JSX, you can do that as well. In React we call
11 | these functions "components" and they have some special properties.
12 |
13 | Components are basically functions which return something that is "renderable"
14 | (more React elements, strings, `null`, numbers, etc.)
15 |
16 | ## Exercise
17 |
18 | Production deploys:
19 |
20 | - [Exercise](http://react-fundamentals.netlify.app/isolated/exercise/04.html)
21 | - [Final](http://react-fundamentals.netlify.app/isolated/final/04.html)
22 |
23 | Let's say the DOM we want to generate is like this:
24 |
25 | ```html
26 |
27 |
Hello World
28 |
Goodbye World
29 |
30 | ```
31 |
32 | In this case, it would be cool if we could reduce the duplication for creating
33 | the React elements for this:
34 |
35 | ```jsx
36 |
{children}
37 | ```
38 |
39 | So we need to make a function which accepts an object argument with a `children`
40 | property and returns the React element. Then you can interpolate a call to that
41 | function in your JSX.
42 |
43 | ```jsx
44 |
{message({children: 'Hello World'})}
45 | ```
46 |
47 | This is not how we write custom React components, but this is important for you
48 | to understand them. We'll get to custom components in the extra credit.
49 |
50 | 📜 Read more
51 |
52 | - [https://reactjs.org/docs/jsx-in-depth.html](https://reactjs.org/docs/jsx-in-depth.html)
53 | - [https://kentcdodds.com/blog/what-is-jsx](https://kentcdodds.com/blog/what-is-jsx)
54 |
55 | ## Extra Credit
56 |
57 | ### 1. 💯 using a custom component with React.createElement
58 |
59 | [Production deploy](http://react-fundamentals.netlify.app/isolated/final/04.extra-1.html)
60 |
61 | So far we've only used `React.createElement(someString)`, but the first argument
62 | to `React.createElement` can also be a function which returns something that's
63 | renderable.
64 |
65 | So instead of calling your `message` function, pass it as the first argument to
66 | `React.createElement` and pass the `{children: 'Hello World'}` object as the
67 | second argument.
68 |
69 | ### 2. 💯 using a custom component with JSX
70 |
71 | [Production deploy](http://react-fundamentals.netlify.app/isolated/final/04.extra-2.html)
72 |
73 | We're so close! Just like using JSX for regular `div`s is nicer than using the
74 | raw `React.createElement` API, using JSX for custom components is nicer too.
75 | Remember that it's Babel that's responsible for taking our JSX and compiling it
76 | to `React.createElement` calls so we just need a way to tell Babel how to
77 | compile our JSX so it passes the function by its name rather than a string.
78 |
79 | We do this by how the JSX appears. Here are a few examples of Babel output for
80 | JSX:
81 |
82 | ```javascript
83 | ui = // React.createElement(Capitalized)
84 | ui = // React.createElement(property.access)
85 | ui = // React.createElement(Property.Access)
86 | ui = // SyntaxError
87 | ui = // React.createElement('lowercase')
88 | ui = // React.createElement('kebab-case')
89 | ui = // React.createElement('Upper-Kebab-Case')
90 | ui = // React.createElement(Upper_Snake_Case)
91 | ui = // React.createElement('lower_snake_case')
92 | ```
93 |
94 | See if you can change your component function name so people can use it with JSX
95 | more easily!
96 |
97 | ### 3. 💯 Runtime validation with PropTypes
98 |
99 | [Production deploy](http://react-fundamentals.netlify.app/isolated/final/04.extra-3.html)
100 |
101 | Let's change the Message component a little bit. Make it look like this now:
102 |
103 | ```javascript
104 | function Message({subject, greeting}) {
105 | return (
106 |
107 | {greeting}, {subject}
108 |
109 | )
110 | }
111 | ```
112 |
113 | So now we'll use it like this:
114 |
115 | ```javascript
116 |
117 |
118 | ```
119 |
120 | What happens if I forget to pass the `greeting` or `subject` props? It's not
121 | going to render properly. We'll end up with a dangling comma somewhere. It would
122 | be nice if we got some sort of indication that we passed the wrong value to the
123 | component. This is what the `propTypes` feature is for. Here's an example of how
124 | you use `propTypes`:
125 |
126 | ```javascript
127 | function FavoriteNumber({favoriteNumber}) {
128 | return
My favorite number is: {favoriteNumber}
129 | }
130 |
131 | const PropTypes = {
132 | number(props, propName, componentName) {
133 | if (typeof props[propName] !== 'number') {
134 | return new Error('Some useful error message here')
135 | }
136 | },
137 | }
138 |
139 | FavoriteNumber.propTypes = {
140 | favoriteNumber: PropTypes.number,
141 | }
142 | ```
143 |
144 | With that, if I do this:
145 |
146 | ```javascript
147 |
148 | ```
149 |
150 | I'll get an error in the console.
151 |
152 | For this extra credit, add `propTypes` support to your updated component
153 | (remember to update it to have the subject and greeting).
154 |
155 | 🦉 Note that prop types validation add some runtime overhead resulting in sub-optimal
156 | performance, so the validation functions are not run in production.
157 |
158 | 📜 Read more about prop-types:
159 |
160 | - [https://reactjs.org/docs/typechecking-with-proptypes.html](https://reactjs.org/docs/typechecking-with-proptypes.html)
161 |
162 | ### 4. 💯 Use the prop-types package
163 |
164 | [Production deploy](http://react-fundamentals.netlify.app/isolated/final/04.extra-4.html)
165 |
166 | As it turns out, there are some pretty common things you'd want to validate, so
167 | the React team maintains a package of these called
168 | [`prop-types`](https://npm.im/prop-types). Go ahead and get that added to the
169 | page by adding a script tag for it:
170 |
171 | ```html
172 |
173 | ```
174 |
175 | Then use that package instead of writing it yourself. Also, make use of the
176 | `isRequired` feature!
177 |
178 | ### 5. 💯 using React Fragments
179 |
180 | [Production deploy](http://react-fundamentals.netlify.app/isolated/final/04.extra-5.html)
181 |
182 | One feature of JSX that you'll find useful is called
183 | ["React Fragments"](https://reactjs.org/docs/fragments.html). It's a special
184 | kind of component from React which allows you to position two elements
185 | side-by-side rather than just nested.
186 |
187 | The component is available via `` (or a
188 | [short syntax](https://reactjs.org/docs/fragments.html#short-syntax) that opens
189 | with `<>` and closes with `>`). Replace the `
` with
190 | a fragment and inspect the DOM to notice that the elements are both rendered as
191 | direct children of `root`.
192 |
193 | ## 🦉 Feedback
194 |
195 | Fill out
196 | [the feedback form](https://ws.kcd.im/?ws=React%20Fundamentals%20%E2%9A%9B&e=04%3A%20Creating%20custom%20components&em=).
197 |
--------------------------------------------------------------------------------
/src/exercise/05.js:
--------------------------------------------------------------------------------
1 | // Styling
2 | // http://localhost:3000/isolated/exercise/05.js
3 |
4 | import * as React from 'react'
5 | import '../box-styles.css'
6 |
7 | // 🐨 add a className prop to each div and apply the correct class names
8 | // based on the text content
9 | // 💰 Here are the available class names: box, box--large, box--medium, box--small
10 | // 💰 each of the elements should have the "box" className applied
11 |
12 | // 🐨 add a style prop to each div so their background color
13 | // matches what the text says it should be
14 | // 🐨 also use the style prop to make the font italic
15 | // 💰 Here are available style attributes: backgroundColor, fontStyle
16 |
17 | const smallBox =
28 | )
29 | }
30 |
31 | export default App
32 |
--------------------------------------------------------------------------------
/src/exercise/05.md:
--------------------------------------------------------------------------------
1 | # Styling
2 |
3 | ## 📝 Your Notes
4 |
5 | Elaborate on your learnings here in `src/exercise/05.md`
6 |
7 | ## Background
8 |
9 | There are two primary ways to style react components
10 |
11 | 1. Inline styles with the `style` prop
12 | 2. Regular CSS with the `className` prop
13 |
14 | **About the `style` prop:**
15 |
16 | - In HTML you'd pass a string of CSS:
17 |
18 | ```html
19 |
20 | ```
21 |
22 | - In React, you'll pass an object of CSS:
23 |
24 | ```jsx
25 |
26 | ```
27 |
28 | Note that in react the `{{` and `}}` is actually a combination of a JSX
29 | expression and an object expression. The same example above could be written
30 | like so:
31 |
32 | ```jsx
33 | const myStyles = {marginTop: 20, backgroundColor: 'blue'}
34 |
35 | ```
36 |
37 | Note also that the property names are `camelCased` rather than `kebab-cased`.
38 | This matches the `style` property of DOM nodes (which is a
39 | [`CSSStyleDeclaration`](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration)
40 | object).
41 |
42 | **About the `className` prop:**
43 |
44 | As we discussed earlier, in HTML, you apply a class name to an element with the
45 | `class` attribute. In JSX, you use the `className` prop.
46 |
47 | ## Exercise
48 |
49 | Production deploys:
50 |
51 | - [Exercise](http://react-fundamentals.netlify.app/isolated/exercise/05.js)
52 | - [Final](http://react-fundamentals.netlify.app/isolated/final/05.js)
53 |
54 | In this exercise we'll use both methods for styling react components.
55 |
56 | We have the following css on the page:
57 |
58 | ```css
59 | .box {
60 | border: 1px solid #333;
61 | display: flex;
62 | flex-direction: column;
63 | justify-content: center;
64 | text-align: center;
65 | }
66 | .box--large {
67 | width: 270px;
68 | height: 270px;
69 | }
70 | .box--medium {
71 | width: 180px;
72 | height: 180px;
73 | }
74 | .box--small {
75 | width: 90px;
76 | height: 90px;
77 | }
78 | ```
79 |
80 | Your job is to apply the right className and style props to the divs so the
81 | styles applied match the text content.
82 |
83 | ## Extra Credit
84 |
85 | ### 1. 💯 Create a custom component
86 |
87 | [Production deploy](http://react-fundamentals.netlify.app/isolated/final/05.extra-1.js)
88 |
89 | Try to make a custom `` component that renders a div, accepts all the
90 | props and merges the given `style` and `className` props with the shared values.
91 |
92 | I should be able to use it like so:
93 |
94 | ```jsx
95 |
96 | small lightblue box
97 |
98 | ```
99 |
100 | The `box` className and `fontStyle: 'italic'` style should be applied in
101 | addition to the values that come from props.
102 |
103 | ### 2. 💯 accept a size prop to encapsulate styling
104 |
105 | [Production deploy](http://react-fundamentals.netlify.app/isolated/final/05.extra-2.js)
106 |
107 | It's great that we're composing the `className`s and `style`s properly, but
108 | wouldn't it be better if the users of our components didn't have to worry about
109 | which class name to apply for a given effect? Or that a class name is involved
110 | at all? I think it would be better if users of our component had a `size` prop
111 | and our component took care of making the box that size.
112 |
113 | In this extra credit, try to make this API work:
114 |
115 | ```jsx
116 |
117 | small lightblue box
118 |
119 | ```
120 |
121 | ## Attribution
122 |
123 | [Matt Zabriskie](https://twitter.com/mzabriskie) developed this example
124 | originally for
125 | [a workshop we gave together.](https://github.com/mzabriskie/react-workshop)
126 |
127 | ## 🦉 Feedback
128 |
129 | Fill out
130 | [the feedback form](https://ws.kcd.im/?ws=React%20Fundamentals%20%E2%9A%9B&e=05%3A%20Styling&em=).
131 |
--------------------------------------------------------------------------------
/src/exercise/06.js:
--------------------------------------------------------------------------------
1 | // Basic Forms
2 | // http://localhost:3000/isolated/exercise/06.js
3 |
4 | import * as React from 'react'
5 |
6 | function UsernameForm({onSubmitUsername}) {
7 | // 🐨 add a submit event handler here (`handleSubmit`).
8 | // 💰 Make sure to accept the `event` as an argument and call
9 | // `event.preventDefault()` to prevent the default behavior of form submit
10 | // events (which refreshes the page).
11 | // 📜 https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault
12 | //
13 | // 🐨 get the value from the username input (using whichever method
14 | // you prefer from the options mentioned in the instructions)
15 | // 💰 For example: event.target.elements[0].value
16 | // 🐨 Call `onSubmitUsername` with the value of the input
17 |
18 | // 🐨 add the onSubmit handler to the
30 | )
31 | }
32 |
33 | function App() {
34 | const onSubmitUsername = username => alert(`You entered: ${username}`)
35 | return
36 | }
37 |
38 | export default App
39 |
--------------------------------------------------------------------------------
/src/exercise/06.md:
--------------------------------------------------------------------------------
1 | # Forms
2 |
3 | ## 📝 Your Notes
4 |
5 | Elaborate on your learnings here in `src/exercise/06.md`
6 |
7 | ## Background
8 |
9 | In React, there actually aren't a ton of things you have to learn to interact
10 | with forms beyond what you can do with regular DOM APIs and JavaScript. Which I
11 | think is pretty awesome.
12 |
13 | You can attach a submit handler to a form element with the `onSubmit` prop. This
14 | will be called with the submit event which has a `target`. That `target` is a
15 | reference to the `
23 | )
24 | }
25 |
26 | function App() {
27 | const onSubmitUsername = username => alert(`You entered: ${username}`)
28 | return
29 | }
30 |
31 | export default App
32 |
--------------------------------------------------------------------------------
/src/final/06.extra-2.js:
--------------------------------------------------------------------------------
1 | // Dynamic Forms
2 | // 💯 Validate lower-case
3 | // http://localhost:3000/isolated/final/06.extra-2.js
4 |
5 | import * as React from 'react'
6 |
7 | function UsernameForm({onSubmitUsername}) {
8 | const [error, setError] = React.useState(null)
9 |
10 | function handleSubmit(event) {
11 | event.preventDefault()
12 | onSubmitUsername(event.target.elements.usernameInput.value)
13 | }
14 |
15 | function handleChange(event) {
16 | const {value} = event.target
17 | const isLowerCase = value === value.toLowerCase()
18 | setError(isLowerCase ? null : 'Username must be lower case')
19 | }
20 |
21 | return (
22 |
34 | )
35 | }
36 |
37 | function App() {
38 | const onSubmitUsername = username => alert(`You entered: ${username}`)
39 | return (
40 |