MIT Weblab笔记 - React Advanced

React Lifecycle

  1. Trigger: First time component is called or State Change

  2. Render: React runs the Javascript code in component and calls subcomponents

  3. Commit: React puts returned JSX into HTML DOM to be served to viewer

  4. Unmounting: React Removes the component from DOM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const Steak = () => {
const [doneness, setDoneness] = useState(0);

// Everything below are called again during re-render
const { name, imgSrc } = steakLookup[doneness];
const sentence = `Here is your ${name} steak!`;

const sendToKitchen = () => {
setDoneness(doneness + 1);
};

return (
<div>
<h2>{sentence}</h2>
<img src={imgSrc} style={{ maxWidth: "500px" }} />
{doneness < 4 && (
<button style={{ fontSize: "24px" }} onClick={sendToKitchen}>
Send Back To Kitchen
</button>
)}
</div>
);
};

When a state is updated, the javascript code in component is executed again, except the state definition lines (Non-state variables don’t persist!)

React Hooks

useEffect()

Syntax

1
2
3
4
5
6
7
8
9
10
11
12
useEffect(
() => {
/*
Do something here,
e.g. interacting with an external service
*/
get("/api/stories").then((storyObjs) => {
setStories(storyObjs);
});
return () => {};
},[/* dependencies */]
);
  • Setting state (defined by useState() hook) is async
  • useEffect() is used to run function every time a variable in dependency array changes
  • Commonly used to load external data into state
  • The return is a callback function that runs when the component dismounts, like cleanup function
1
2
3
4
5
6
7
const myFunction = () => {
// Do something
};

useEffect(myFunction, [var1, var2]); // Calls myFunction every time var1 or var2 changes
useEffect(myFunction, []); // Calls myFunction only once when the component is rendered for the first time (on mount)
useEffect(myFunction); // Calls myFunction at every render (first component call + every time any state changes)

Router (Reach Router)

Routers select a child to render based on the child’s path. The children are just other components that could be rendered on their own outside of a Router. We usually define the <Router> part in the <App> component.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from "react"
import { render } from "react-dom"
import { Router, Link } from "@reach/router"

let Home = () => <div>Home</div>
let Dash = () => <div>Dash</div>
let Team = () => <div>Team</div>

render(
<Router>
<Home path="/" /> // root
<Dash path="dashboard" /> // append "dashboard" to the end of the current url
<Team path="/team" /> // root + "/team"
<NotFound default /> // display the NotFound component if the URL is undefined
</Router>
)
  • The path / represents the homepage or the main entry point of the application.
  • This path starts with a / indicates it is an absolute path from the root of the application.

We can add links to nav bars.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let Home = () => (
<div>
<h1>Home</h1>
<nav>
<Link to="/">Home</Link>
<Link to="dashboard">Dashboard</Link>
</nav>
</div>
)

let Dash = () => <div>Dash</div>

render(
<Router>
<Home path="/" /> // root path
<Dash path="dashboard" /> // relative path
</Router>
)

Control Flow

How to dynamically render different JSX based on conditions? For example, I want a component looks different depending on the state value.

In JSX, we cannot directly use control flow statements like if, for, or while within the curly braces ({}). This is because these JavaScript control flow statements do not return a value. They are considered statements rather than expressions in JavaScript. The following ways can help us control what the component renders (What is inside JSX):

Assign JSX fragements to JavaScript variables

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function outOfBandJSX(option) {
var optionJSX;
if (option) {
optionJSX = <div>Option was True</div>;
} else {
optionJSX = <div>Option was False</div>;
}
var listItems = [];
for (var i = 0; i < 3; i++) {
listItems[i] = <li key={i}>List Item {i}</li>;
}
var retVal =
<div>
{optionJSX}
<ul>
{listItems}
</ul>
</div>;

return retVal;
}
  • The function combines the conditional JSX fragment and the list of items into a single return value. The retVal variable is a JSX fragment that includes both the conditionally rendered optionJSX and the dynamically generated listItems. This JSX is returned by the function and can be rendered in the component.
  • Then we can include {this.outOfBandJSX(true)} or {this.outOfBandJSX(false)} in the JSX to effectively control what we want.
1
2
3
4
5
6
7
let greeting; 
const en = "Hello";
const sp = <b>Hola</b>;
let {useSpanish} = this.prop;
if (useSpanish) {greeting = sp} else {greeting = en};

<div>{greeting}</div>

Embedding the operations inside of curly braces

1
2
3
4
5
6
return (
<div>
<h1>Title</h1>
<p>{loading ? "Loading..." : "Actual page content"}</p>
</div>
);
  • Although arbitrary JavaScript can appear inside braces, it must return a string or JSX expression to work. The ?: operator always return a value.
  • If loading is true, it displays the text “Loading…”.
  • If loading is false, it displays “Actual page content”.

Short-circuit boolean operations

1
2
3
4
5
6
7
8
9
10
11
<div>
<p>A paragraph will appear between this paragraph</p>
{
this.state.inputValue && (
<p>This text will appear when this.state.inputValue is truthy.
this.state.inputValue === {this.state.inputValue}
</p>
)
}
<p>... and this one when some characters are typed into the input box below.</p>
</div>
  • If this.state.inputValue is true, the right-hand-side of && will be executed, a new <p> element will be rendered. Else, nothing will be rendered.

Rendering an Array of Data

Key

1
2
3
4
5
6
7
8
storiesList = stories.map((storyObj) => (
<Card
key={`Card_${storyObj._id}`}
_id={storyObj._id}
creator_name={storyObj.creator_name}
content={storyObj.content}
/>
));
  • the “key” prop is a special attribute you need to include when creating lists of elements. Keys help React identify which items have changed, are added, or are removed, improving efficiency of rendering
  • In this case, the key is a unique string that combines the word “Card_” with the unique identifier _id from the storyObj

Return an array of html elements

1
2
3
4
5
6
7
8
const data = [
{ id: 0, text: "My favorite food is doritos" },
{ id: 1, text: "I like nachos because they look like doritos" },
];

return data.map((item) => {
return <div key={item.id}>{item.text}</div>;
});

Return an array of components

1
2
3
4
5
6
const data = [
{ id: 0, text: "My favorite food is doritos" },
{ id: 1, text: "I like nachos because they look like doritos" },
];

return data.map((item) => <ItemComponent key={item.id}>{item.text}</ItemComponent>);
  • Reasons for Using key in React Lists: This allows React to determine which elements have changed, added, or removed and to update only the necessary parts of the DOM. Without keys, React would need to re-render the entire list, which can be inefficient.

Input using DOM-like handlers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: ''
};
}

handleChange = (event) => {
this.setState({ inputValue: event.target.value });
}

render() {
return (
<input type="text" value={this.state.inputValue} onChange={this.handleChange} />
);
}
}
  • type="text": This specifies that the input field is for text input.
  • value={this.state.inputValue}: This binds the value of the input field to the inputValue property in the component’s state.
  • The onChange event is triggered every time the user types something in the input field.

MIT Weblab笔记 - React Advanced
https://thiefcat.github.io/2024/07/04/MIT-Weblab/React-Advanced/
Author
小贼猫
Posted on
July 4, 2024
Licensed under