# React
Links: [[Javascript]]
- Peter Hunt - Rethinking best practices, 2013
- https://www.youtube.com/watch?v=x7cQ3mrcKaY&t=1511s
- Overview of docs and related resources: https://reactjs.org/docs/getting-started.html
- Installation of React, React-Dom, and [[JSX]]
- https://reactjs.org/docs/add-react-to-a-website.html
- Install [[Babel]] using the [[Babel]] instructions; the React docs introduces 8 vulnerabilities
-
## Intro Examples
https://reactjs.org/
### A Simple Component
```jsx
class HelloMessage extends React.Component {
render() {
return (
<div>
Hello {this.props.name}
</div>
);
}
}
ReactDOM.render(
<HelloMessage name="Taylor" />,
document.getElementById('hello.example')
);
```
- A new html tag called `HelloMessage` extends `React.Component` by implementing the `render()` function
- `name` is a parameter and is passed in via the DOM as an attribute `name="Taylor"`
- `this.props.name` used to refer to properties
- `JSX` allows pseudohtml to be used with javascript
### A Stateful Component
```jsx
class Timer extends React.Component {
constructor(props) {
super(props);
this.state = { seconds: 0 };
}
tick() {
this.setState(state => ({
seconds: stats.seconds + 1
}));
}
componentDidMount() {
this.interval = setInterval(() => this.tick(), 1000)
}
}
```
- A more complicated example overrides the `constructor(props)` method
- The constructor initializes the timer to 0
- Don't forget to call `super()` inside the constructor
- `tick()` implements the incrementing
- `componentDidMount()` sets the interval for `this.tick()`
- "When a component’s state data changes, the rendered markup will be updated by re-invoking `render()`."
### An Application
```jsx
class TodoApp extends React.Component {
// Define state and event handlers to modify that state
constructor(props) {
super(props);
this.state = { items: [], text: '' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
render() {
return (
<div>
<h3>TODO</h3>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<label htmlFor="new-todo">
What needs to be done?
</label>
<input id="new-todo"
onChange={this.handleChange}
value={this.state.text}
/>
<button>
Add #{this.state.items.length + 1}
</button>
</form>
</div>
)
}
handleChange(e) {
this.setState({ text: e.target.value })
}
handleSubmit(e) {
e.preventDefault();
if (this.state.text.length === 0) {
return;
}
const newItem = {
text: this.state.text,
id: Date.now(),
}
this.setState(state => ({
items: state.items.concat(newItem),
text: '',
})
}
}
class TodoList extends React.Component {
render() {
return (
<ul>
{this.props.items.map(item => (
<li key={item.id}>{item.text}</li>
))}
</ul>
)
}
}
ReactDOM.render(
<TodoApp />,
document.getElementById('todos-example')
);
```
- Define state and event handlers to modify that state
- Use `this.setState` to modify the state by passing in a function that takes the current state as input and outputs a new state
### A Component Using External Plugins
```jsx
class MarkdownEditor extends React.Component {
constructor(props) {
super(props);
this.md = new Remarkable();
this.handleChange = this.handleChange.bind(this);
this.state = { value: 'Hello, **world**!' };
}
handleChange(e) {
this.setState({ value: e.target.value });
}
getRawMarkup() {
return { __html: this.md.render(this.state.value) };
}
render() {
return (
<div className="MarkdownEditor">
<h3>Input</h3>
<label htmlFor="markdown-content">
Enter some markdown
</label>
<textarea
id="markdown-content"
onChange={this.handleChange}
defaultValue={this.state.value}
/>
<h3>Output</h3>
<div
className="content"
dangerouslySetInnerHTML={this.getRawMarkup()}
/>
</div>
);
}
}
ReactDOM.render(
<MarkdownEditor />,
document.getElementById('markdown-example')
);
```
## State FAQs
https://reactjs.org/docs/faq-state.html
### What is the difference between `state` and `props`?
`props` (short for “properties”) and `state` are both plain JavaScript objects. While both hold information that influences the output of render, they are different in one important way: `props` get passed to the component (similar to function parameters) whereas `state` is managed within the component (similar to variables declared within a function).
### Why is `setState` giving me the wrong value?
Calls to `setState` are asynchronous - don’t rely on `this.state` to reflect the new value immediately after calling `setState`. Pass an updater function instead of an object if you need to compute values based on the current state (see below for details).
Pass a function instead of an object to `setState` to ensure the call always uses the most updated version of state (see below).
### What is the difference between passing an object or a function in `setState`?
Passing an update function allows you to access the current state value inside the updater. Since `setState` calls are batched, this lets you chain updates and ensure they build on top of each other instead of conflicting:
```js
incrementCount() {
this.setState((state) => {
// Important: read `state` instead of `this.state` when updating.
return {count: state.count + 1}
});
}
handleSomething() {
// Let's say `this.state.count` starts at 0.
this.incrementCount();
this.incrementCount();
this.incrementCount();
// If you read `this.state.count` now, it would still be 0.
// But when React re-renders the component, it will be 3.
}
```
### When is `setState` asynchronous?
Currently, `setState` is asynchronous inside event handlers.
This ensures, for example, that if both `Parent` and `Child` call `setState` during a click event, `Child` isn’t re-rendered twice. Instead, React “flushes” the state updates at the end of the browser event. This results in significant performance improvements in larger apps.
This is an implementation detail so avoid relying on it directly. In the future versions, React will batch updates by default in more cases.
## When should I use [[Redux]]?
https://redux.js.org/faq/general#when-should-i-use-redux
As Pete Hunt, one of the early contributors to React, says:
> You'll know when you need Flux. If you aren't sure if you need it, you don't need it.
Similarly, Dan Abramov, one of the creators of Redux, says:
> I would like to amend this: don't use Redux until you have problems with vanilla React.
## Thinking in React
https://reactjs.org/docs/thinking-in-react.html
- Good overview of the development process
- "Many React users credit reading Thinking in React as the moment React finally “clicked” for them. It’s probably the oldest React walkthrough but it’s still just as relevant."
### Step 1: Break The UI Into A Component Hierarchy
You’ll see here that we have five components in our app. We’ve italicized the data each component represents.
1. **`FilterableProductTable` (orange):** contains the entirety of the example
2. **`SearchBar` (blue):** receives all _user input_
3. **`ProductTable` (green):** displays and filters the _data collection_ based on _user input_
4. **`ProductCategoryRow` (turquoise):** displays a heading for each _category_
5. **`ProductRow` (red):** displays a row for each _product_
Now that we’ve identified the components in our mock, let’s arrange them into a hierarchy. Components that appear within another component in the mock should appear as a child in the hierarchy:
- `FilterableProductTable`
- `SearchBar`
- `ProductTable`
- `ProductCategoryRow`
- `ProductRow`
### Step 2: Build A Static Version in React
> If you’re familiar with the concept of _state_, **don’t use state at all** to build this static version.
> It’s best to decouple these processes because building a static version requires a lot of typing and no thinking, and adding interactivity requires a lot of thinking and not a lot of typing. We’ll see why.
## Step 3: Identify The Minimal (but complete) Representation Of UI State
> To build your app correctly, you first need to think of the minimal set of mutable state that your app needs. The key here is [DRY: _Don’t Repeat Yourself_](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself). Figure out the absolute minimal representation of the state your application needs and compute everything else you need on-demand. For example, if you’re building a TODO list, keep an array of the TODO items around; don’t keep a separate state variable for the count. Instead, when you want to render the TODO count, take the length of the TODO items array.
Let’s go through each one and figure out which one is state. Ask three questions about each piece of data:
1. Is it passed in from a parent via props? If so, it probably isn’t state.
2. Does it remain unchanged over time? If so, it probably isn’t state.
3. Can you compute it based on any other state or props in your component? If so, it isn’t state.
So finally, our state is:
- The search text the user has entered
- The value of the checkbox
## Step 4: Identify Where Your State Should Live
OK, so we’ve identified what the minimal set of app state is. Next, we need to identify which component mutates, or _owns_, this state.
Remember: React is all about one-way data flow down the component hierarchy. It may not be immediately clear which component should own what state. **This is often the most challenging part for newcomers to understand,** so follow these steps to figure it out:
For each piece of state in your application:
- Identify every component that renders something based on that state.
- Find a common owner component (a single component above all the components that need the state in the hierarchy).
- Either the common owner or another component higher up in the hierarchy should own the state.
- 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 owner component.
Let’s run through this strategy for our application:
- `ProductTable` needs to filter the product list based on state and `SearchBar` needs to display the search text and checked state.
- The common owner component is `FilterableProductTable`.
- It conceptually makes sense for the filter text and checked value to live in `FilterableProductTable`
Cool, so we’ve decided that our state lives in `FilterableProductTable`. First, add an instance property `this.state = {filterText: '', inStockOnly: false}` to `FilterableProductTable`’s `constructor` to reflect the initial state of your application. Then, pass `filterText` and `inStockOnly` to `ProductTable` and `SearchBar` as a prop. Finally, use these props to filter the rows in `ProductTable` and set the values of the form fields in `SearchBar`.
## Step 5: Add Inverse Data Flow
So far, we’ve built an app that renders correctly as a function of props and state flowing down the hierarchy. Now it’s time to support data flowing the other way: the form components deep in the hierarchy need to update the state in `FilterableProductTable`.
React makes this data flow explicit to help you understand how your program works, but it does require a little more typing than traditional two-way data binding.
If you try to type or check the box in the current version of the example, you’ll see that React ignores your input. This is intentional, as we’ve set the `value` prop of the `input` to always be equal to the `state` passed in from `FilterableProductTable`.
Let’s think about what we want to happen. We want to make sure that whenever the user changes the form, we update the state to reflect the user input. Since components should only update their own state, `FilterableProductTable` will pass callbacks to `SearchBar` that will fire whenever the state should be updated. We can use the `onChange` event on the inputs to be notified of it. The callbacks passed by `FilterableProductTable` will call `setState()`, and the app will be updated.
### And That’s It
Hopefully, this gives you an idea of how to think about building components and applications with React. While it may be a little more typing than you’re used to, remember that code is read far more than it’s written, and it’s less difficult to read this modular, explicit code. As you start to build large libraries of components, you’ll appreciate this explicitness and modularity, and with code reuse, your lines of code will start to shrink. :)
## Minifying
### How to minify the React library (only in production): Create React App
https://reactjs.org/docs/optimizing-performance.html#create-react-app
Requires [Create React App](https://github.com/facebook/create-react-app), which is probably not necessary for [[-Projects/-Lightning Router/Lightning Router]]
- In [[-Projects/-Lightning Router/Lightning Router]], just going to directly use the production versions instead.
### How to minify your own scripts
https://gist.github.com/gaearon/42a2ffa41b8319948f9be4076286e1f3
```bash
npm init -y (only needs to be run once)
npm install terser
npx terser -c -m -o example.min.js -- example.js
```
#### With babel
Use `babel-preset-minify`
https://babeljs.io/docs/en/babel-preset-minify
```bash
npm install --save-dev @babel/preset-env
```
In `.babelrc`
```json
{
"presets": ["minify"]
}
```
## Creating a Toolchain from Scratch
https://reactjs.org/docs/create-a-new-react-app.html
A JavaScript build toolchain typically consists of:
- A **package manager**, such as [Yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/). It lets you take advantage of a vast ecosystem of third-party packages, and easily install or update them.
- A **bundler**, such as [webpack](https://webpack.js.org/) or [Parcel](https://parceljs.org/). It lets you write modular code and bundle it together into small packages to optimize load time.
- A **compiler** such as [Babel](https://babeljs.io/). It lets you write modern JavaScript code that still works in older browsers.
We currently have 1 and 3 for [[-Projects/-Lightning Router/Lightning Router]] - not sure the rest is needed yet
Guide on creating [[React]] toolchain from scratch, has a section on [[webpack]]:
- https://medium.com/@JedaiSaboteur/creating-a-react-app-from-scratch-f3c693b84658
## More Notes
### Parse Error: Adjacent JSX elements must be wrapped in an enclosing tag
https://stackoverflow.com/questions/31284169/parse-error-adjacent-jsx-elements-must-be-wrapped-in-an-enclosing-tag
Basically: there can only be 1 root element returned as part of `render()`, if there are adjacent (i.e. sibling) elements, put them both under a `<div>`
### State updates are merged
https://reactjs.org/docs/state-and-lifecycle.html#state-updates-are-merged
- Therefore, you only need to pass in the keys that you want to change
When you call `setState()`, React merges the object you provide into the current state. For example, your state may contain several independent variables:
```jsx
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
}
```
Then you can update them independently with separate `setState()` calls:
```jsx
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
```
The merging is shallow, so `this.setState({comments})` leaves `this.state.posts` intact, but completely replaces `this.state.comments`.
## Forms
https://reactjs.org/docs/forms.html
### Prevent page reload upon form submit
Use the `preventDefault()` method
```jsx
class PurchaseForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
// Prevent page refresh on form submit
event.preventDefault();
}
render() {
return (
<div>
<h3>Purchase form</h3>
<form onSubmit={this.handleSubmit}>
<button type="submit"
class="btn btn-primary">
Request invoice
</button>
</form>
</div>
);
}
}
```