<info 340/>
React Apps
Joel Ross
Spring 2024
If you're struggling with a problem set, ask for help!
Test and check your work in the browser
Only run Jest when the problem set is finished and functional
View of the Day
-
Project Draft 2 details
-
Building an App from scratch (code demo)
- Defining components
- Passing data as props
- etc.
-
Adding interactivity
Project Draft 2
What we are looking for: Refactored Draft 1 into a React App
Converted the HTML/CSS from draft 1 into a published React app. Began to add interactive functionality.
- App is built: Ran create-react-app, etc. See assignment for details
- ALL of content rendered: You should have Components that render DOM for every part of your page
- Has Components w/ props and data: Organize your Components! Can hard-code sample data for now
- Has 1 feature almost implemented: Includes event handling and state manipulation (today)
- Fixes issues from draft 1: You're revising the HTML/CSS, fix problems while you're at it!
-
Published to Firebase hosting: get that working this draft
(see assignment for details; demo next week)
# 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.
Updating Lecture Code
Create React App
create-react-app is a command line application that generates scaffolding ("starter code") for a React website.
# EITHER create a new react app
npx create-react-app app-name --use-npm
# OR install dependencies for existing project
cd path/to/project
npm install
# run the server
npm start
Runs a script that starts a development server which will:
- Automatically transpile React code into pure JavaScript
- Combine (bundle) different modules into a single file
- Show build and syntax errors in the console, including style warnings
- Automatically reload the page (replaces live-server)!
Let's make a chat app!
Let's make a chat app!
Properties (props
)
function MessageItem(props) {
const message = props.message; //access the prop
//can use prop for logic or processing
const messageUpper = message.toUpperCase();
return <li>{messageUpper}</li>; //render based on prop
}
ReactDOM.createRoot(document.getElementById('root'))
.render(<MessageItem message="Be quiet" />)
Inside the Component function definition, all the passed in props are passed in as a single argument object (conventionally called props)
ALL props stored in this object
Props and Composition
function MessageList(props) {
//msgComponents will be an array of components!
const msgComponents = props.messages.map((msgStr) => {
const elem = <MessageItem message={msgStr} key={msgStr} />; //pass prop down!
return elem
}
return (
<ul>
{/* An array of components renders as siblings */}
{msgComponents}
</ul>
);
}
const messagesArray = ["Hello world", "No borders", "Go huskies!"];
ReactDOM.createRoot(document.getElementById('root'))
.render(<MessageList messages={messagesArray} />)
Props will often need to be "passed down" to child components. A common pattern is to map an array of prop values to an array of children components to render!
unique "id" for the element
React Style Guidelines
Conditional Rendering
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>
)
}
React Events
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(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 = 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>;
}
DOM Interactivity
//The current "state"
const state = {
data: [ {}, {}, {} ],
...
}
//define presentation - lots of these kinds of functions
function renderData() {
//render all the data
//...
}
//define user interaction
button.addEventListener('click', function() {
//MODIFY THE STATE
state.data[i] = ...;
//CLEAR OLD VIEW AND RE-RENDER CONTENT
document.querySelector('#main').innerHTML = '';
renderData(); //RE-RENDER CONTENT
})
changeable data lives out here
1. modify the state data
2. re-render the view
2. re-render the view
On button click, do 2 things:
In addition to the props, React components can also track their internal state. This keeps track of information about the Component that may change due to user interaction.
React State
State is reserved only for interactivity, that is, data that changes over time
Some examples of state data:
- The sorted order of child components
- Timers or dynamic content
- Which model data are shown!
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.
Using State Hooks
//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
Naming Conventions Matter!
In order to write correct React (that can be understood
and debugged by you and others), you need to follow the naming conventions:
- The argument to a Component function is called props (with an s)
- A "state-setter" function for state variable foo is called setFoo (replacing "foo" with the state variable name)
Changing State
React state is changed asynchronously (for speed). Calling a "state-setter" function (when ready) and automatically re-render the Component (by calling the function again).
function CountingButton(props) {
const [count, setCount] = useState(3) //initial value of 3
const handleClick = (event) => {
setCount(4); //change `count` to 4 AND re-render!
console.log(count); //will output "3";
//state has not changed yet!
}
console.log(count); //will have "current" value of state
//3 first render, 4 after clicking
return (
<button onClick={handleClick}>Clicked {count} times</button>
);
}
Debugging State
Because state changes are asynchronous, you can only "see" them after the component has re-rendered. Use console logs at the "rendering" step to debug
function CountingButton(props) {
const [count, setCount] = useState(3) //initial value of 3
console.log("DEBUG: count", count); //debug! variable here,
//after re-render
const handleClick = (event) => {
setCount(count + 1); //incremenet count AND re-render!
//do not debug variable here!
}
return (
<button onClick={handleClick}>Clicked {count} times</button>
);
}
Multiple State Variables
Components can (and often do) contain multiple state variables.
//Example from React documentation
function ExampleWithManyStates(props) {
//Declare multiple state variables!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
//...
}
state variable is an array of objects!
State & Arrays/Objects
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) => {
if(index == 0) { //transform objects if needed
todoObject.text = "Fix bugs"
}
return todoObject; //return object to go into new array
})
setTodos(todosCopy) //This works!
}
//...
}
Props vs State
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).
-
Is the value passed in from a parent via props? If so, it probably isn’t state.
-
Does the value remain unchanged over time? If so, it definitely isn’t state.
- Can you compute it based on any other state or props in your component? If so, it definitely isn’t state.
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).
Action Items!
Action Items!
-
Read/Review Ch 16-17: React & Interactive React
-
Problem Set 07 due next Wednesday
-
Do not put this off! Start now!
-
You can do problem-a and (mostly) problem-b
-
-
Project Draft 2 due week from Friday
-
Convert Draft 1 into React Components!
-
Add one interactive feature
-
Next time: (more) Interactive React!
info340sp24-react-apps
By Joel Ross
info340sp24-react-apps
- 279