# switch to starter branch to get new starter code
git checkout starter
# download new starter code
git pull
# switch back to main branch for coding
git checkout main
# merge in new starter code (use default msg)
git merge starter --no-edit
# code and enjoy!
Get the starter code from the starter branch, but do all of your work on main.
Vite provides a development server which will:
# Make sure you are in the project directory
cd path/to/project
# Install dependencies for existing project (installs vite)
npm install
# Run the development server script
npm run dev -- --host
We add user interaction in React the same way as with the DOM: by listening for events and executing callback functions when they occur.
function MyButton() {
//A function that will be called when clicked
//The name is conventional, but arbitrary.
//The callback will be passed the DOM event as usual
const handleClick = function(event) {
console.log("clicky clicky");
}
//make a button with an `onClick` attribute!
//this "registers" the listener and sets the callback
return <button onClick={handleClick}>Click me!</button>;
}
special React prop
can only put listeners on HTML
elements, not Components!
function MyButton(props) {
//A function that will be called when clicked
//The name is conventional, but arbitrary.
//The callback will be passed the DOM event as usual
const handleClick = (event) => {
console.log("clicky clicky");
}
//make a button with an `onClick` attribute!
//this "registers" the listener and sets the callback
return <button onClick={handleClick}>Click me!</button>;
}
You add state to a component by using a state hook. The hook defines a "state variable" which will retain its value across Component function calls, as well as a function to update that variable.
//import the state hook function `useState()` to define state
import React, { useState } from 'react';
function CountingButton(props) {
const [count, setCount] = useState(0);
const handleClick = (event) => {
setCount(count+1); //update the state to be a new value
//and RE-RENDER the Component!
}
return (
<button onClick={handleClick}>Clicked {count} times</button>
);
}
state variable
update function
initial value for variable
props are for information that doesn’t change from the Component’s perspective, including “initial” data. state is for information that will change, usually due to user interaction (see React FAQ).
props are for information that doesn’t change from the Component’s perspective, including “initial” data. state is for information that will change, usually due to user interaction (see React FAQ).
To allow child components to "update" the parent's state, pass them a callback function as a prop.
Style Guide: do not pass a state setter function directly.
function App(props) {
const [data, setData] = useState([]);
const addItemToData = (newItem) => {
const newData = [...data, newItem]; //copy via spread
setData(newData); //update state
}
return (
<FruitButton callback={addItemToData} text={"Apple"} />
<FruitButton callback={addItemToData} text={"Banana"} />
)
}
function FruitButton(props) {
//what to do when clicked
const handleClick = (event) => {
//call given callback, passing in given text
props.callback(props.text);
}
return (
<button onClick={handleClick}>{props.text}</button>
)
}
State variables will only be updated if a different value is passed to the setter function. For arrays and objects, pass a copy of the element with an updated element or property.
function TodoListWithError(props) {
//a state value that is an array of objects
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
const handleClick = (event) => {
todos[0].text = "Fix bugs"; //modify the object
//but don't make a new one
setTodos(todos) //This won't work! Not "changing"
}
//...
}
function TodoList(props) {
//a state value that is an array of objects
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
const handleClick = (event) => {
//create a copy of the array using the `map()` function
const todosCopy = todos.map((todoObject, index) => {
const objCopy = {...todoObject}; //copy object as well
if(index == 0) { //transform objects if needed
objCopy.text = "Fix bugs"
}
return objCopy; //return object to go into new array
})
setTodos(todosCopy) //This works!
}
//...
}
You can use control logic (if statements) to specify whether or not a component should be rendered.
function ConditionalPanel(props) {
//assign element to show to variable
let thingToRender = null; //null element will not render
if(conditionOne){ //based on props or state
thingToRender = <OptionA />
} else if(conditionTwo) {
thingToRender = <OptionB />
} else if(conditionThree) {
return null; //show nothing!
}
//keep return statement as simple as possible!
return (<div>{thingToRender}</div>);
}
function ConditionPanel(props) {
//can use inline expressions via shortcutting. Not recommended
return (
<div>
{conditionOne == true && <OptionA />}
</div>
)
}
If multiple components rely on the same
data (variable), you should "lift up" that
state
to a shared parent, who can pass the information back down as
props
.
ChildA
ChildB
Parent
Has Data
(state)
Needs Data
<ChildA data={data} />
Has Data (prop)
Has Data (prop)
<ChildA data={data} />
Has Data (state)
React components are structured to be self-contained, re-usable elements... so there are lots of pre-defined components online you can use!
In order to use a component in your app:
npm install lib-name
import { ComponentName } from 'lib-name'
<ComponentName />
Much of the web (and software in general) is built on shared, reusable libraries.
Complete task list for Week 8 (all items!)
Review Ch 15-16: React & Interactive React
Problem Set 07 due Friday
Next week
Problem Set 08 due Wednesday
Project Draft 2 due Friday
Next time: Router (multiple pages & navigation!)