elf-notes/content/react/_index.md

217 lines
8.6 KiB
Markdown

+++
title = "React Notes"
description = "Basic documentation for React"
date = 2022-06-22T18:00:00+00:00
updated = 2022-06-22T18:00:00+00:00
template = "section.html"
sort_by = "weight"
weight = 6
draft = false
[taxonomies]
documentation=["Reference"]
categories=["React", "single-page-applications"]
+++
[React](https://reactjs.org/) is a Javascript library for creating dynamic and
responsive websites. It is the most popular of the current generation of SPA
(Single Page Application) tools, and it's the one I use professionally.
## Starting a project
React is installed using [npm](https://npmjs.com). You have three principle
choices when it comes to installing React: You can install it the basic way by
creating a new project folder and running `npm install react react-dom` (the
latter is for web-based projects rather than `react-native` projects for Android
and IOs), you can use a project template (my preferred technique, but it
requires routine updating), and using
[create-react-app](https://create-react-app.dev), which includes an entire
framework for React, including a hot-loader for development, pre-configured
tooling for ESLint, Prettier, and a host of other code-quality features.
Personally, I have always found that create-react-app is limiting in too many
ways; eventually, I end up not even using the CRA "eject" feature (which
converts the implicit configuration hidden in the `node_modules` folder into
explicit configuration); instead, I create a new project, copy the `src` folder
from the CRA project into that, and construct a new toolchain around it, one
that isn't cluttered by all the other things found in CRA and one that is
configured to my exact specficiation.
## A Mental Model for React
[Caveat: This is a mental model for *React*. Once you start adding a whole
bunch of tooling on top of React, you're on your own.]
A React application has a collection of one or more *states*. A complex
application may have orthoganal states: the user's identity, tracking the page
they're currently looking at, one or more forms the customer has interact with,
and so on. React listens to these states and, where you have specified that a
state change has a consequential visual change on the page, React automatically
updates the page.
All input from React should be channeled up to the aggregate collection of
states, and your React app should be written such that it correctly responds to
that change. It's a singular loop with no internal contradictions.
React creates a tree internally that describes the visual result of the current
state. When you update the state, that tree is rebuilt, compared to the
previous version, and only those parts of the HTML that are directly affected
are updated.
Never forget: React's output is a tree. React's behavior is an event loop. React
is a recursive engine operating on a recursive data structure, it manipulates
another recursive data structure (the browser's Document Object Model, or DOM),
and success depends upon *your* data being able to fit into that exact same
model.
## JSX
``` typescript
import React from "react";
import ReactDOM from "react-dom";
const Hello = <h1>Hello, World!</h1>;
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Hello />);
```
This is the smallest possible React program that shows React and JSX. JSX is an
XML-like addition that you write directly into your Javascript. All JSX
functions begin with a capital letter, to distinguish from plain old HTML, which
is always begun with a lower case letter. That `Hello` is a function; under the
covers, the JSX parser turns it into a bit of code that generates the HTML and,
if specified, hooks up event handlers.
Git is project and folder-centered, and to start using git go to the root folder
of a project you want to place under source control and initialize it:
```bash
$ mkdir a-new-project
$ touch README.md
$ git init
```
This creates a new folder, `.git`, where Git will store your commit history and
some configuration details. Git will usually not create a repository without
_something_ to store in it, but see the [`git start` alias](#config) below.
## Putting files into git
To put files under source control, you must add them. To update the entire
folder, switch to the root of the project and add _all_ of it:
```bash
$ git add .
$ git commit
```
An editor will pop-up, asking you what this commit is about. It's generally
polite, especially if you're working in a team, to explain your commit in some
detail-- and to generally keep the commit small, in order to ensure that you
don't have to explain too much!
If your commit message could be a single line, you can add it directly from the
command line:
```bash
$ git add .
$ git commit -m "Updated the widget to widgetize."
```
... and you can even combine both commands, but be careful: this command will
not add any files that are new. It will only commit existing files that have
been modified, and will delete any files that you have deleted, from the
repository. (Deleted files still exist in the history and can always be
recovered.)
```bash
$ git commit -am "Updated the widget to widgetize."
```
## Git Configuration {#config}
You can have a global Git configuration file, `$HOME/\.gitconfig`, in which you
keep your personal information and command aliases, which is one of three ways
you can add your own commands to Git.
```bash
[user]
name = Elf M. Sternberg
email = someguy@example.com
[alias]
unstage = reset -q HEAD --
nevermind = !git reset --hard HEAD && git clean -d -f
wip = for-each-ref --sort='authordate:iso8601' --format='%(color:green)%(authordate:relative)%09%(color:white)%(refname:short)' refs/heads
stem = "!f() { git checkout -b $1 develop; }; f"
start = !git init && git commit --allow-empty -m \"Initial commit\"
```
## Git Aliases {#aliases}
Aliases are commands that you can run *in git* as if they were part of the git
toolset, but their functionality is defined by you. The five aliases shown
above are my "must haves." They represent the way I work.
- `unstage` is something I do a lot. Maybe it's my ADHD, but I often add
something to the git staging area, then realize that the work was incomplete
and have to go back. This command does that, and I hated memorizing it.
- `nevermind` is for when your work has gone off the rails; your stab at solving
the problem has taken you places you didn't want to be. This command resets
you to exactly where you were before you started hacking.
- `wip` stands for "works in progress"; it shows you a list of branches
currently live in your local project, in the order from oldest to newest, with
a text that tells you your last commit was "yesterday" or "3 months ago".
- `stem` creates a new branch off the develop branch (you can change that to
main or canon or whatever). This is the most common workflow I have at home,
and this command allows me to get to it quickly. The syntax tells git to use
the bash to populate the new branch name, as the default alias format can
only take arguments at the end, and the new branch name must be injected
before the source branch.
- `start` creates a git repository out of a completely empty folder. This might
seem odd, but it's actually a very useful way of introducing a new project and
ensuring git is ready to go.
## Git Extensions
Just like aliases, you can add whole unique commands to git, as long as the
extension name doesn't conflict with one of git's internal commands. The
syntax for doing so is to create a script (in any language!) and name it
`git-your-extension-name`, and you call it by invoking git and giving it the
extension name.
For example, if you write documentation and you want to know how many words
you've written since your last commit, you can create a Bash script named
`git-wc` (word count):
``` bash
#!/bin/bash
REM=`git diff --word-diff=porcelain -U $* | grep '^-' | sed 's/^-//' | wc -w`
ADD=`git diff --word-diff=porcelain -U $* | grep '^+' | sed 's/^+//' | wc -w`
DIF=`expr $ADD - $REM`
echo "Word count: $DIF"
```
## Add vs Commit
You may have noticed that there's a two-step to committing your work; you `add`
it, then `commit` it. `add`ing it puts it into the `staging area`. The primary
goal of this design is to allow you to commit only parts of your project, rather
than committing everything at once. By creating an index of what-to-commit, and
then allowing you to write your commit message afterward, you have more control
over the development process.
If you're completely reassured of your skillz as a _leet koder dood_, you could
always create an alias that stages, commits, and pushes to your remote
repository all at once. I don't recommend that.