React (65 h)
INFO
Currently reading Fluent React by Tejas Kumar.
To learn
React Router Tutorial v6.22.3 (+3 h)
Tutorial v6.22.3 | React Router
About form
A <button type="button">
, while seemingly redundant, is the HTML way of preventing a button from submitting its form.
Browsers can serialize forms by the name
attribute of it's input elements. The name of this input is q
, that's why the URL has ?q=
. If we named it search
the URL would be ?search=
. Note that this form is different from the others we've used, it does not have <form method="post">
. The default method
is "get"
. That means when the browser creates the request for the next document, it doesn't put the form data into the request POST body, but into the URLSearchParams
of a GET request.
export async function action({ request, params }) {
const formData = await request.formData();
const updates = Object.fromEntries(formData);
updates.first; // "Some"
updates.last; // "Name"
// ...
}
Object.fromEntries
can collect formData
all into an object. Aside from action
, none of these APIs we're discussing are provided by React Router: request
, request.formData
, Object.fromEntries
are all provided by the web platform.
Navigation states
<NavLink
to={`contacts/${contact.id}`}
className={({ isActive, isPending }) =>
isActive ? "active" : isPending ? "pending" : ""
}
>
Placeholder
</NavLink>
Use a NavLink
in the sidebar. Note that we are passing a function to className. When the user is at the URL in the NavLink
, then isActive
will be true. When it's about to be active (the data is still loading) then isPending
will be true.
useNavigation
to add global pending UI. useNavigation
returns the current navigation state: it can be one of "idle" | "submitting" | "loading"
.
The Two Reacts (+1 h)
When you build a user interface, you need to be able to respond to at least some interactions with guaranteed low latency and with zero network roundtrips.
UI is made of components, but we argued for two very different visions:
UI = f(state)
wherestate
is client-side, andf
runs on the client. This approach allows writing instantly interactive components like<Counter />
. (Here,f
may also run on the server with the initial state to generate HTML.)UI = f(data)
wheredata
is server-side, andf
runs on the server only. This approach allows writing data-processing components like<PostPreview />
. (Here,f
runs categorically on the server only. Build-time counts as “server”.)
Modern Redux (+2 h) (Draft)
Redux has changed a lot. Redux Toolkit (also known as "RTK" for short) is now the official recommended approach for writing Redux logic. Let's relearn Redux.
Details
Part 1: Redux Overview and Concepts
Redux is a library for managing global application state:
- Redux is typically used with the React-Redux library for integrating Redux and React together
- Redux Toolkit is the recommended way to write Redux logic
Redux terminology:
- Action: a plain JavaScript object that has a
type
fieldjsconst addTodoAction = { type: "todos/todoAdded", payload: "Buy milk", };
- _Action Creator_: a function that creates and returns an _action_ object
```js
const addTodo = (text) => {
return {
type: "todos/todoAdded",
payload: text,
};
};
```
- _Reducer_: a function that receives the current _state_ and an _action_ object, decides how to update the state if necessary, and returns the new state: `(state, action) => newState`
- [Detailed Explanation: Why are they called 'Reducers'?](https://redux.js.org/tutorials/essentials/part-1-overview-concepts#reducers)
- _Dispatch_: `dispatch` an _action_ to update the _state_
- _Selector_: a function to extract specific states
```js
const selectCounterValue = (state) => state.value;
const currentValue = selectCounterValue(store.getState());
console.log(currentValue);
// 2
```
Redux uses a "one-way data flow" app structure:
![Redux data flow](/redux-data-flow.gif)
### Part 2: Redux Toolkit App Structure
```js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "../features/counter/counterSlice";
export default configureStore({
reducer: {
counter: counterReducer,
},
});
```
When we pass in an object like `{counter: counterReducer}`, that says that we want to have a `state.counter` **section** of our Redux state object, and that we want the `counterReducer` function to be **in charge of** deciding if and how to update the `state.counter` section whenever an action is dispatched.
::: info
When we pass an object of slice reducers to `configureStore`, it passes those to `combineReducers` for us to generate the root reducer. To learn the details, take a look at [Detailed Explanation: Reducers and State Structure](https://redux.js.org/tutorials/essentials/part-2-app-structure#redux-slices)
:::
**A "slice" is a collection of Redux reducer logic and actions for a single feature in your app**.
```js
import { createSlice } from "@reduxjs/toolkit";
export const counterSlice = createSlice({
name: "counter",
initialState: {
value: 0,
},
reducers: {
increment: (state) => {
// Redux Toolkit allows us to write "mutating" logic in reducers. It
// doesn't actually mutate the state because it uses the immer library,
// which detects changes to a "draft state" and produces a brand new
// immutable state based off those changes
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
});
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;
```
The `counterSlice` object returned by `createSlice()` has properties:
- `counterSlice.actions`: an object of **action creators**, which are usually called when using `dispatch` or `reducer` function
- `counterSlice.reducer`: passed to `configureStore` to be in charge of some state section
::: danger
You can only write "mutating" logic in Redux Toolkit's `createSlice` and `createReducer` because they use Immer inside! If you write mutating logic in reducers without Immer, it will mutate the state and cause bugs!
:::
Before (+62 h)
My React journey started in July 2020. There're some special times spent:
- The first encounter with React - the official tutorial and onboarding pratice at my first job, took approximately 20 h
- A Complete Guide to useEffect by Dan Abramov - 5 h
- Deconstructing React by Tejas Kumar - 3 h
- Build your own React by Rodrigo Pombo. I followed this article to build my own React for about 10 h.
- React mentoring program 2022 with my colleague Addy Zhou, where I learned Redux for the first time. - 24 h