If you have a lot of HTML to port to JSX, you can use an online converter.
You'll get two things from useState: the current state (count), and the function that lets you update it (setCount).
- To "remember" things, components use state.
- To make the UI interactive, you need to let users change your underlying data model. You will use state for this.
Which of these are state? Identify the ones that are not:
- Does it remain unchanged over time? If so, it isn't state.
- Is it passed in from a parent via props? If so, it isn't state.
- Can you compute it based on existing state or props in your component? If so, it definitely isn't state!
After identifying your app's minimal state data, you need to identify which component is responsible for changing this state, or owns the state .
For each piece of state in your application:
- Identify every component that renders something based on that state.
- Find their closest common parent component---a component above them all in the hierarchy.
- Decide where the state should live:
- Often, you can put the state directly into their common parent.
- You can also put the state into some component above their common parent.
- If you can't find a component where it makes sense to own the state, create a new component solely for holding the state and add it somewhere in the hierarchy above the common parent component.
You can find other built-in Hooks in the API reference.
Hooks are more restrictive than other functions. You can only call Hooks at the top of your components (or other Hooks). If you want to use useState in a condition or a loop, extract a new component and put it there.
A JSX element is a combination of JavaScript code and HTML tags that describes what you'd like to display.
To "escape into JavaScript" from JSX, you need curly braces. Add curly braces around value in JSX like so:
javascript
function Square({ value }) {
return <button className="square">{value}</button>;
}
React DevTools let you check the props and the state of your React components.
When you were passing onSquareClick={handleClick}
, you were passing the handleClick function down as a prop. You were not calling it! But now you are calling that function right away---notice the parentheses in handleClick(0)
--- and that's why it runs too early. You don't want to call handleClick until the user clicks! Instead, let's do this: <Square value={squares[0]} onSquareClick={() => handleClick(0)} />
. Notice the new () => syntax
. Here, () => handleClick(0)
is an arrow function, which is a shorter way to define functions.
In React, it's conventional to use onSomething names for props which represent events and handleSomething for the function definitions which handle those events.
**Why immutability is important?**Note how in handleClick, you call .slice()
to create a copy of the squares array instead of modifying the existing array?
https://react.dev/learn/tutorial-tic-tac-toe#why-immutability-is-important
You can learn more about how React chooses when to re-render a component in the memo API reference.
https://react.dev/reference/react/memo
When you render a list, React stores some information about each rendered list item. When you update a list, React needs to determine what has changed. You could have added, removed, re-arranged, or updated the list's items. React is a computer program and does not know what you intended, so you need to specify a key property for each list item to differentiate each list item from its siblings. When a list is re-rendered, React takes each list item's key and searches the previous list's items for a matching key . If the current list has a key that didn't exist before, React creates a component. If the current list is missing a key that existed in the previous list, React destroys the previous component. If two keys match, the corresponding component is moved.
https://react.dev/learn/tutorial-tic-tac-toe#picking-a-key
Using the array index as a key is problematic when trying to re-order a list's items or inserting/removing list items?
To implement a UI in React, you will usually follow the same five steps.
Step 1: Break the UI into a component hierarchy
Step 2: Build a static version in React
Step 3: Find the minimal but complete representation of UI state
Step 4: Identify where your state should live
Step 5: Add inverse data flow
https://react.dev/learn/thinking-in-react
In simpler examples, it's usually easier to go top-down, and on larger projects, it's easier to go bottom-up.
You can learn all about handling events and updating state in the Adding Interactivity section.
https://react.dev/learn/adding-interactivity
- Responding to events
- State: a component's memory
- Render and commit
- State as a snapshot
- Queueing a series of state updates
- Updating objects in state
- Updating arrays in state
state as a snapshot:
javascript
console.log(count); // 0
setCount(count + 1); // Request a re-render with 1
console.log(count); // Still 0!
Read State as a Snapshot to learn why state appears "fixed" and unchanging inside the event handlers.
https://react.dev/learn/state-as-a-snapshot
updater function:
javascript
console.log(score); // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score); // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score); // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score); // 0
can fix this by passing an updater function when setting state.
javascript
function increment() {
setScore(s => s + 1);
}
update objects:
Usually, you will use the ...
spread syntax to copy objects and arrays that you want to change.
javascript
const [person, setPerson] = useState({
name: 'Niki de Saint Phalle',
artwork: {
title: 'Blue Nana',
city: 'Hamburg',
image: 'https://i.imgur.com/Sd1AgUOm.jpg',
}
});
function handleNameChange(e) {
setPerson({
...person,
name: e.target.value
});
}
function handleTitleChange(e) {
setPerson({
...person,
artwork: {
...person.artwork,
title: e.target.value
}
});
}
If copying objects in code gets tedious, you can use a library like Immer to reduce repetitive code:
GitHub - immerjs/use-immer: Use immer to drive state with a React hooks
javascript
import { useImmer } from 'use-immer';
const [person, updatePerson] = useImmer({
name: 'Niki de Saint Phalle',
artwork: {
title: 'Blue Nana',
city: 'Hamburg',
image: 'https://i.imgur.com/Sd1AgUOm.jpg',
}
});
function handleNameChange(e) {
updatePerson(draft => {
draft.name = e.target.value;
});
}
function handleTitleChange(e) {
updatePerson(draft => {
draft.artwork.title = e.target.value;
});
}
update arrays:
Arrays are another type of mutable JavaScript objects you can store in state and should treat as read-only.
javascript
const [list, setList] = useState(
initialList
);
function handleToggle(artworkId, nextSeen) {
setList(list.map(artwork => {
if (artwork.id === artworkId) {
return { ...artwork, seen: nextSeen };
} else {
return artwork;
}
}));
}
If copying arrays in code gets tedious, you can use a library like Immer to reduce repetitive code:
javascript
import { useImmer } from 'use-immer';
const [list, updateList] = useImmer(initialList);
function handleToggle(artworkId, nextSeen) {
updateList(draft => {
const artwork = draft.find(a =>
a.id === artworkId
);
artwork.seen = nextSeen;
});
}