Year #2, Week #2 đť đď¸
New stuff we learned this week: đ¤
React: Mapping over Arrays
- a very common pattern in React is to map over an array, producing a series of components. Imagine you have this dataset:
const cars = [
{ name: "Honda Accord", color: "blue", miles: 80000 },
{ name: "Jeep Cherokee", color: "yellow", miles: 20000 },
{ name: "Ford Taurus", color: "black", miles: 50000 },
];
- if you wanted to make a component out of the data from each element in the array, you can map over the array, returning a React component for each item:
const App: React.FC = () => {
return (
<div>
<h1>Cars</h1>
<ul>
{cars.map(({ name, color }) => {
return <Car name={car.name} color={car.color} />;
})}
</ul>
</div>
);
};
- the only problem with the above code is that React will complain about not getting separate keys for each item in the array. React needs this for itâs internal housekeeping and updating of your component. To keep React happy, you have to give every mapped-over component a key unique for that array (not unique for the whole component or your whole app), like this:
/* ... */
cars.map(({ name, color }) => {
return <Car key={name} name={name} color={color} />;
});
/* ... */
- notice that I re-used the
name
property for both thekey
and thename
prop. Thatâs fine! I know the name is unique, and it was handy, so I used it! - just like in a normal arrow function, if you have just one expression and want to return it, you can omit the curly braces and
return
statement. That means the above could be written like this as well:
/* ... */
cars.map(({ name }) => <Car key={name} name={name} />);
/* ... */
- the mapping function is just a regular-old javascript function, so you can write code in there and return any arbitrary JSX you like:
/* ... */
cars.map(({ name, color, miles }) => {
const isClunker = miles > 75000;
return (
<div key={name} className={isClunker ? `clunker` : ``}>
<h2>{name}</h2>
<h3>Color: {color}</h3>
</div>
);
});
/* ... */
- notice above on line 5 I still had to provide the
key
prop, which must go on the outermost element of whatever youâre returning from the map function.
React: Events
- in vanilla DOM-scripting, if you want to listen for and respond to user events like clicks, you need to use
element.addEventListener('click', someHandler)
. In React, we put these handler functions directly in the JSX, and React behind the scenes turns them into DOM event listeners for us! The most common event to listen for is a âclickâ. Every normal HTML element in React supports aonClick
prop which takes a function:
function logHello() {
console.log("Hello!");
}
const App: React.FC = () => {
return (
<div>
<h1 onClick={logHello}>click me!</h1>
</div>
);
};
- but itâs much more common to use arrow functions for click handlers:
const App: React.FC = () => {
return (
<div>
<h1 onClick={() => console.log("Hi")}>click me!</h1>
</div>
);
};
- there are other event props you can use like
onDoubleClick
,onContextMenu
(right-click),onMousenter
,onMouseleave
, etc. Some special html elements get their own special event props that make sense for them, for instance on<input />
elements you can doonChange
. - a very common use of event handlers in React is to update component state using a setter provided by
useState()
(see below for more)
React: useState
- another super basic tool that React gives you is the ability to manage the STATE of your components over time. The most basic way to do this is using a built-in hook provided by React called
useState
. The basic API is this:
import React, { useState } from "react";
/* ... later on, down inside a Component ... */
const [currentVal, setNewVal] = useState(initialValue);
- that is to say, calling
useState()
returns you back a tuple. The first element is always guaranteed to be the current value of that piece of state. The second element is a function to change (set) the state. Hereâs a simple example:
const [timesClicked, setTimesClicked] = useState(0);
- very commonly, you would use some sort of event handler (like an
onClick
function) to update the state. Hereâs an example of a simple counter component that displays how many times a button has been clicked, and updates the count when the button is clicked:
const Counter: React.FC = () => {
const [timesClicked, setTimesClicked] = useState(0);
return (
<div onClick={() => setTimesClicked(timesClicked + 1)}>
<p>I have been clicked {timesClicked} times.</p>
</div>
);
};
React: Fragments
- in your first week playing with React, you may have come across this cryptic error:
jsx expressions must have one parent element
. That error turns up when you create a component that is not contained within one element, like this:
const BadComponent: React.FC = () => {
return (
<h1>This is bad!</h1>
<p>This will cause an error!</p>
);
}
- itâs hard to see why thatâs a problem, but it has to do with how JSX is turned back into javascript under the hood. The problem is that the
BadComponent
is returning TWO elements, anh1
andp
. To fix it, we can just wrap it in some other element, like a<div>
(note lines 3 and 6):
const GoodComponent: React.FC = () => {
return (
<div>
<h1>This is good!</h1>
<p>Error will be gone, thanks div!</p>
</div>
);
};
- the sad thing about this is sometimes we donât want an extra
div
in our markup!. In that case, React lets us use a special dissapearing element called a Fragment. It works like this:
const GoodComponent: React.FC = () => {
return (
<React.Fragment>
<h1>This is good!</h1>
<p>Error will be gone, thanks div!</p>
</React.Fragment>
);
};
- using
React.Fragment
instead of adiv
keeps away the error messages, without adding an extra div in the final markup. Hooray! đ - and if you donât like typing
React.Fragment
â you can also do it just like this:
const GoodComponent: React.FC = () => {
return (
<>
<h1>This is good!</h1>
<p>Error will be gone, thanks div!</p>
</>
);
};
- those weird
<>
and</>
are the same as writing<React.Fragment>
and</React.Fragemtent>
, and they are less to type, and look a bit more like the reality that these tags are actually nothing.
React: Style Prop
- in normal HTML, you can write inline css using the style attribute like so:
<div style="color: red; margin-top: 3em;">
<h1>Foobar</h1>
</div>
- in React, every primitive HTML element supports a
style
prop, but the difference is you pass it an object with camel-cased CSS rules, like so:
const Component: React.FC = () => {
return (
<div style={{ color: "red", marginTop: "3em" }}>
<h1>Foobar</h1>
</div>
);
};
- TAKE NOTE: make sure you notice the double curly braces, they are required. The outer curly braces switch you into javascript mode, and the inner braces are the outside of the object.
React: useEffect
- React has another hook called
useEffect
that is used for doing side-effecty sorts of things. Hereâs an example where we update theCounter
component from an example in thesetState
section, so that we run the âside-effectâ of setting the web pageâs<title>
tag:
import React, { useEffect } from "react";
const Counter: React.FC = () => {
const [timesClicked, setTimesClicked] = useState(0);
// here's us making a side-effect
useEffect(() => {
// update document title tag using the browser's API
document.title = `You clicked ${timesClicked} times`;
});
return (
<div onClick={() => setTimesClicked(timesClicked + 1)}>
<p>I have been clicked {timesClicked} times.</p>
</div>
);
};
useEffect
is a function that takes one or two arguments. The first argument is a function to run and the second argument is a list of dependencies that react uses to know how often to run your effect. Weâll learn more about it in the weeks to come. For now, if you learn two facts, itâs good enough to get started:- fact one: if you do not supply the second argument (like in the example above) your effect function will run every time the component renders
- fact two: if you supply an empty array as the second argument (
[]
), then your effect will run once and only once, the first time the component renders.
useEffect()
It can be used for lots of things, but a very common use-case is to make a network request to an API to fetch some data, when it is often combined withuseState()
:
import React, { useEffect } from "react";
const App: React.FC = () => {
const [cats, setCats] = useState([]);
useEffect(() => {
fetch("http://api.cats.com")
.then(response => response.json())
.then(catsJson => setCats(catsJson));
}, []); // <- notice 2nd argument! will run EXACTLY ONCE
return (
<div>
<h1>Cats</h1>
{cats.map(cat => (
<Cat name={cat.name} key={cat.name} />
))}
</div>
);
};
Useful Links:
Homework Plan
- 1 day review all flashcards
- 1 day touch typing practice
- 4 days Execute Program homework
- 2 days react homework
Homework
Execute Program Homework
- visit Execute Programâs website and register for an account (itâs free). Youâll need to supply your email, and probably click a link that is sent to that email address.
- once you click the link in your email, select the Typescript course
- get started reading and answering the prompts
- four times this week, come back to Execute Progam (it will send you an email reminder every day) and do at least one new lesson plus any reviews that it makes you do.
- when you come back to do Execute Program on a new day, it will start by making you quickly review something from a lesson you have already completed. Always do the review first (I donât think it gives you another option), but after the review is done, do at least one NEW lesson each day. So, every day (except the very first) will consist of:
- whatever review the program gives you
- at least one new lesson
- if you have time and interest, you can do more than one lesson in the beginning, but:
- donât do more than 3 per day, it will hurt your learning to go so fast
- after a while, the program will only let you do one new lesson each day with paying, so youâll be stuck at that point.
React Homework #1: React Cars đ
- slowly and carefully review all the âNew Stuffâ above.
- make a fork of this repo
ssh
into your home dir, create a directory called~/y2-w2
cd
into that dir and clone your fork of the repo- checkout a new branch Harriet, that means you too!
- connect to that directory with Vscode
- Youâre going to be creating a simple React app copying this webpage
- read these hints and requirements FIRST
- after you connect with vscode, checkout
./src/data.ts
â thatâs going to be your data source for your app. Itâs an ARRAY of objects. - youâll need to mount the react app with
ReactDOM.render()
inindex.tsx
. If you forgot how to do that, refer to last weeks âNew Stuffâ - I want you to create 3 components:
<App />
,<Car />
, and<SeePrice />
, each in a separate file. - in the
App
component, you will need to map over the data passing props down to a<Car />
component for each item in the data array. - donât forget the special
key
prop! - you must use the
color
property of each car object to set the background color of your<Car />
component using thestyle
prop. - youâll need to attach a click handler to the
SeePrice
component, so that italert
s the price, like my example. - make sure your
SeePrice
component changes color on hover, like mine - spin up the dev server with
npm start
while youâre working, and when youâre done, runnpm run build
, just like last week.
- after you connect with vscode, checkout
- Kiah Credit: ⨠add some state to this app: make a button that says âGive me a discountâ. After the user clicks it, all the prices should be cut in half.
- commit your work
- run
npm run build
which will build your app tohttp://<yourname>.howtocomputer.link/react-cars
- push up a MR, and slack #homework with the MR url and your website URL.
React Homework #2: React State
- slowly and carefully review all the âNew Stuffâ above.
- make a fork of this repo
ssh
into your home dir, cd into the~/y2-w2
dir and clone your fork of the repo- checkout a new branch Harriet, that means you too!
- connect to that directory with Vscode
- play around for a second with my example website. Click all the buttons.
- in vscode, install your dependencies and spin up the dev server
- you should see that you already have most of my example app, except the buttons donât do anything.
- your job is to use
useState
and click handlers to make the buttons on your site work like the example webpage. - Extra Credit: ⨠- change the behavior of the app so that the number is never allowed to go below zero.
- Kiah Credit: ⨠- make it so that every time the number is divisible by
5
the number changes color - commit your work
- run
npm run build
which will build your app tohttp://<yourname>.howtocomputer.link/react-state
- push up a MR, and slack #homework with the MR url and your website URL.