-
-
Notifications
You must be signed in to change notification settings - Fork 15.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Docs Rewrite] Create the "Quick Start" page #3675
Changes from 8 commits
6ebed7f
bae55be
d201489
503c15d
e813599
6063b94
09542a3
6428359
9a08a9f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import React from 'react' | ||
|
||
export const DetailedExplanation = ({ children }) => { | ||
return ( | ||
<details className="detailed-explanation"> | ||
<summary> | ||
<h4>Detailed Explanation</h4> | ||
</summary> | ||
{children} | ||
</details> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import React from 'react' | ||
|
||
const types = ['info', 'success', 'warning', 'error'] | ||
|
||
export const Note = ({ children, type = 'info' }) => { | ||
const className = types.includes(type) ? type : 'info' | ||
|
||
return <blockquote className={className}>{children}</blockquote> | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import React from 'react' | ||
|
||
export const TestComponent = () => <div style={{ color: 'red' }}>Testing!</div> |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,337 @@ | ||||||
--- | ||||||
id: quick-start | ||||||
title: Quick Start | ||||||
sidebar_label: Quick Start | ||||||
hide_title: true | ||||||
--- | ||||||
|
||||||
import Tabs from '@theme/Tabs' | ||||||
import TabItem from '@theme/TabItem' | ||||||
|
||||||
import { DetailedExplanation } from '../components/DetailedExplanation' | ||||||
import { Note } from '../components/Note' | ||||||
|
||||||
# Quick Start | ||||||
|
||||||
<Note> | ||||||
|
||||||
### What You'll Learn | ||||||
|
||||||
- What Redux is, and why you should use it | ||||||
- How Redux relates to React | ||||||
- How to set up and start using Redux quickly | ||||||
- What a small working React+Redux app looks like | ||||||
|
||||||
### Prerequisites | ||||||
|
||||||
There are several things you should know in advance before learning Redux: | ||||||
|
||||||
- Basic familiarity with HTML & CSS, and the DOM. | ||||||
- Basic knowledge of JavaScript and programming. | ||||||
- Familiarity with ES6 syntax and features. | ||||||
- Basic knowledge of React, including components, props, and state. | ||||||
- Node.js and `npm` installed globally. | ||||||
|
||||||
</Note> | ||||||
|
||||||
## What Is Redux? | ||||||
|
||||||
**Redux** is a predictable state container for JavaScript apps. It acts as the data layer inside an application. | ||||||
|
||||||
It helps you write applications that behave consistently and can run in different environments (client, server, and native). | ||||||
It also helps you to write code that is testable, and enables you to better understand when, where, why, and how the data in your | ||||||
application has changed. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know the "predictable state container" is the official descriptor but to a newcomer I don't think it means much. I think I'd jump right to the big why:
|
||||||
|
||||||
Redux does this by asking you to: | ||||||
|
||||||
- Place some data (**_"state"_**) into a special object called a **_"store"_** | ||||||
- Write separate functions called **_"reducers"_** that know how to update the state inside the store | ||||||
- Follow specific rules for how your code can update and read the state | ||||||
|
||||||
### What does Redux include? | ||||||
|
||||||
The core Redux library consists of a few API functions. The most important API is the `createStore` function. | ||||||
|
||||||
<Note type="error"> | ||||||
|
||||||
**TODO** figure out what else to put here, or if this should be dropped | ||||||
|
||||||
</Note> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally I don't think this section is needed in a quick start, since it's specifically for getting something quickly rather than overviewing the whole API, which I think the rest of the docs introduce well enough |
||||||
|
||||||
### How does Redux work with a UI? | ||||||
|
||||||
Redux, by itself, is a plain JavaScript library. You can use Redux together with React, or with any other UI view library. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I get the impression that the vast majority of people use Redux with React, and the second sentence makes it clear that it works with other libraries. I'd make the title "How does Redux work with React?" to align with most people's expectations and make it feel like they're in the right place. |
||||||
|
||||||
To help make this possible, there are additional bindings libraries that connect together a Redux store and your UI components. Each different | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This "To help make this possible..." sentence could be cut - this guide isn't going to cover other bindings libraries (I think?). The next sentence makes it clear enough imo. |
||||||
UI framework has its own specific bindings library. For example, the [React-Redux library](https://react-redux.js.org) allows your React components to read values from a Redux store, | ||||||
and tell the store to calculate an update to the state inside. | ||||||
|
||||||
### What is Redux Toolkit? | ||||||
|
||||||
Redux itself is small and unopinionated. We also have a separate addon package called [Redux Toolkit](https://redux-toolkit.js.org), which includes some opinionated defaults | ||||||
that help you use Redux more effectively, and includes packages that we think are essential to building a Redux app. | ||||||
It's our official recommended approach for writing Redux logic. As with the Redux core, you can use Redux Toolkit with any UI layer. | ||||||
|
||||||
## Goals | ||||||
|
||||||
We're going to create a small application with React and Redux together. The app will be a simple employee database, and we'll learn: | ||||||
|
||||||
- How to set up Redux with React | ||||||
- The data flow lifecycle of a Redux app | ||||||
- How to write Redux logic that updates data, and shows the updated data in the UI | ||||||
- How to create, update, view, and delete users (employees) from the system | ||||||
- How to make API calls for each of the above actions | ||||||
|
||||||
## Setup and Installation | ||||||
|
||||||
### Create a React Project | ||||||
|
||||||
We'll start by creating an empty React project. You can do this in one of two ways: creating a local project on your own computer with the | ||||||
Create-React-App tool, or creating a project in the CodeSandbox web app. | ||||||
|
||||||
#### Create a Local Project with Create-React-App | ||||||
|
||||||
[Create-React-App](https://create-react-app.dev/) is the official tool for creating new React projects. | ||||||
|
||||||
Create a new React project named `redux-employee-example` by running this command: | ||||||
|
||||||
```bash | ||||||
npx create-react-app redux-employee-example | ||||||
``` | ||||||
|
||||||
Then, install the required Redux packages, using either the NPM or Yarn package manager: | ||||||
|
||||||
<Tabs | ||||||
defaultValue="npm" | ||||||
values={[ | ||||||
{ label: 'NPM', value: 'npm', }, | ||||||
{ label: 'Yarn', value: 'yarn', } | ||||||
] | ||||||
}> | ||||||
|
||||||
<TabItem value="npm"> | ||||||
|
||||||
```bash | ||||||
npm install @reduxjs/toolkit react-redux | ||||||
``` | ||||||
|
||||||
</TabItem> | ||||||
|
||||||
<TabItem value="yarn"> | ||||||
|
||||||
```bash | ||||||
yarn add @reduxjs/toolkit react-redux | ||||||
``` | ||||||
|
||||||
</TabItem> | ||||||
|
||||||
</Tabs> | ||||||
|
||||||
#### Create an Online Project with CodeSandbox | ||||||
|
||||||
[CodeSandbox.io](https://codesandbox.io) is an online IDE that lets you create entire web applications in your browser, without needing to | ||||||
install anything locally. | ||||||
|
||||||
Create a new React project sandbox by browsing to the [CodeSandbox "Create Sandbox" page](https://codesandbox.io/s/) and selecting the official React template. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Link directly to https://codesandbox.io/s/new for a new React app so we can skip the "browsing" instructions. |
||||||
|
||||||
Once the sandbox has been created, click the "Add Dependency" button on the left, search for `@reduxjs/toolkit`, add it, and then do the same for `react-redux`. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could add a screenshot/GIF here? |
||||||
|
||||||
### Create a Redux Store | ||||||
|
||||||
The React project starts with a single `<App>` component that shows some "hello" text on the page. Our first goal is to create a Redux store instance | ||||||
that holds some data inside, and update the `<App>` component to read that data and show it instead. | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it'd be good to show a full working React example before adding the Redux store. Maybe something with state. Presumably, landing people on this page have used React a little. Ideally they have, anyway. Starting with a React example and "refactoring it to Redux" would:
|
||||||
<Note type="success"> | ||||||
|
||||||
#### Key Concept: "Store" | ||||||
|
||||||
A Redux **_store_** is a special object that holds some data inside, such as a list of users that was fetched from the server. | ||||||
The data inside the store object is called **_state_**. | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could add some kind of visual here to hammer home the idea that the store holds the state. Nit below: "Each Redux store..." kind of implies that an app might have more than one. "A" or "Every" might be better? |
||||||
Each Redux store has three functions that you can call to interact with it: | ||||||
|
||||||
- `store.getState()` returns the current state value inside the store | ||||||
- `store.dispatch()` lets you tell the store that something has happened, and it should calculate a new state value in response | ||||||
- `store.subscribe()` lets you run some code whenever the store has been updated | ||||||
|
||||||
</Note> | ||||||
|
||||||
To create a Redux store, start by updating the `index.js` file to import the `configureStore` function from the `@reduxjs/toolkit` package. | ||||||
|
||||||
```js {3} | ||||||
import React from 'react' | ||||||
import ReactDOM from 'react-dom' | ||||||
import { configureStore } from '@reduxjs/toolkit' | ||||||
|
||||||
import App from './App' | ||||||
|
||||||
const rootElement = document.getElementById('root') | ||||||
ReactDOM.render(<App />, rootElement) | ||||||
``` | ||||||
|
||||||
In order to actually create a Redux store, we need to define our first "reducer" function. | ||||||
|
||||||
<Note type="success"> | ||||||
|
||||||
#### Key Concept: "Reducers" | ||||||
|
||||||
A **_reducer_** is a function that know how to calculate a new state value when asked. A Redux store requires a single reducer function | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "A reducer is a function that calculates a new state value." |
||||||
when it is created, which we call the "root reducer" to say that it is the starting point for any other reducer functions inside. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe skip talking about "root reducers" until later. Get one working first before revealing that there can be a tree of them. |
||||||
|
||||||
Every reducer is called with two arguments: the current `state`, and an object called an **`action`**. We'll look at actions a bit later. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mention here that the reducer "returns the new computed state". Could also add a few words to describe actions so it's not gnawing at them - "...an object called an action that describes how to update the state" |
||||||
|
||||||
Reducers must always follow certain rules inside. As a quick summary: | ||||||
|
||||||
- Reducers must always return a state value, never `undefined` | ||||||
- Reducers can only decide what the next state value should be by looking at the `state` and `action` arguments | ||||||
- Reducers are not allowed to make changes to the `state` argument, or anything else. They can only create the new state value by making copies of the originals, and updating the copies. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be confusing to Redux Toolkit users (and we recommend it to beginners), as mutations are supported via Immer and are recommended in the docs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah this is a good point. Later on, it would be good to show "here's the hard way (ignoring that immer is installed)" and "here's the easy way because of immer". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, this is still my number one concern with trying to explain use of RTK in general, and especially in this page. |
||||||
|
||||||
</Note> | ||||||
|
||||||
For now, we can create a small root reducer function that always returns a string, like this: | ||||||
|
||||||
```js {7-9} | ||||||
import React from 'react' | ||||||
import ReactDOM from 'react-dom' | ||||||
import { configureStore } from '@reduxjs/toolkit' | ||||||
|
||||||
import App from './App' | ||||||
|
||||||
function rootReducer(state, action) { | ||||||
return 'Hello Redux!' | ||||||
} | ||||||
|
||||||
const rootElement = document.getElementById('root') | ||||||
ReactDOM.render(<App />, rootElement) | ||||||
``` | ||||||
|
||||||
Now we can create our first Redux store. We pass in the `rootReducer` function as a parameter. The store will call the reducer function, | ||||||
take whatever value it returns, and save that value inside as the current "state". We can then ask the store what its current state value is. | ||||||
|
||||||
```js {11-15} | ||||||
import React from 'react' | ||||||
import ReactDOM from 'react-dom' | ||||||
import { configureStore } from '@reduxjs/toolkit' | ||||||
|
||||||
import App from './App' | ||||||
|
||||||
function rootReducer(state, action) { | ||||||
return 'Hello Redux!' | ||||||
} | ||||||
|
||||||
const store = configureStore({ | ||||||
reducer: rootReducer | ||||||
}) | ||||||
|
||||||
console.log(store.getState()) | ||||||
|
||||||
const rootElement = document.getElementById('root') | ||||||
ReactDOM.render(<App />, rootElement) | ||||||
``` | ||||||
This comment was marked as resolved.
Sorry, something went wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My intent is to have the first step simply be |
||||||
|
||||||
If you look at the console in your browser's DevTools (or in CodeSandbox), you should see that the words `"Hello Redux!"` were printed. | ||||||
|
||||||
### Set Up the Provider Component | ||||||
|
||||||
We've got a Redux store with its state inside, but now we need to find a way to use that state inside our `<App>` component. | ||||||
|
||||||
It's _possible_ that we could move the store into a separate file, import that store into the `App.js` file, and call `store.getState()`. But, as the | ||||||
app gets bigger, we'd have to import the store into _every_ file. That's not a good idea. | ||||||
Comment on lines
+244
to
+245
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure how useful this information is to a beginner? Just comes off as more information than needed IMO There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mmm... yes and no. My thought was to justify why React-Redux's API is needed at all. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess I'm just worried about this "Quick Start" page having more content than it needs, since in my mind the goal of this page is to provide as minimal information as possibly needed to get started with Redux + React. If you feel like this content fits that goal then we should definitely keep it 😃 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've seen a lot of beginners try to use vanilla Redux in React apps and they get very confused with how to handle the store. I agree with Mark here that it's important for us to explain why React Redux is helpful right away. Of course, if we have a guide for non-React users in the future, this wouldn't be necessary. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this stays, it'd be good to explain why "That's not a good idea." - it will get messy? hard to manage? but there's an easier way? |
||||||
|
||||||
This is where the React-Redux library comes in. It gives us a way to read data from the store in any component in our application, without needing | ||||||
to import the store into every file. | ||||||
|
||||||
To do this, we need to pass the store into a React-Redux `<Provider>` component. | ||||||
|
||||||
<Note type="success"> | ||||||
|
||||||
#### Key Concept: `<Provider>` | ||||||
|
||||||
The React-Redux library has a `<Provider>` component. It uses [React's context API](https://reactjs.org/docs/context.html) to pass the Redux store | ||||||
to all components inside of itself. | ||||||
|
||||||
Every React-Redux app needs to put a `<Provider>` component around the main `<App>` component so that the whole app can use the store. | ||||||
|
||||||
</Note> | ||||||
|
||||||
We'll import the `Provider` component type from React-Redux, render a `<Provider>` around our `<App>`, and then pass the store to the `<Provider>`. (We'll also remove the console log, since we don't need that any more.) | ||||||
|
||||||
```js {4,18-25} | ||||||
import React from 'react' | ||||||
import ReactDOM from 'react-dom' | ||||||
import { configureStore } from '@reduxjs/toolkit' | ||||||
import { Provider } from 'react-redux' | ||||||
|
||||||
import App from './App' | ||||||
|
||||||
function rootReducer(state, action) { | ||||||
return 'Hello Redux!' | ||||||
} | ||||||
|
||||||
const store = configureStore({ | ||||||
reducer: rootReducer | ||||||
}) | ||||||
|
||||||
const rootElement = document.getElementById('root') | ||||||
|
||||||
ReactDOM.render( | ||||||
<Provider store={store}> | ||||||
<App /> | ||||||
</Provider>, | ||||||
rootElement | ||||||
) | ||||||
``` | ||||||
|
||||||
### Show the State in the App Component | ||||||
|
||||||
The last step for the initial setup is to update our `<App>` component to read the state value from the Redux store. | ||||||
|
||||||
We've already seen that the React-Redux `<Provider>` component makes the store available to any components inside. To go along with that, React-Redux | ||||||
includes a React hook called `useSelector`, which React function components can call to retrieve the state values from the store. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should link to the React hooks API docs here. Might also be worth mentioning that React hooks is a pre-req for this page, since the end user could be new to the React hooks API as well. |
||||||
|
||||||
<Note type="success"> | ||||||
|
||||||
#### Key Concept: "Selectors" | ||||||
|
||||||
A **_selector_** is a function that takes the Redux store state as an argument, and returns some part of that store state. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It quite literally "selects" a portion of the state. |
||||||
|
||||||
The React-Redux `useSelector()` hook takes a selector function, calls the selector by passing in the store state, and then returns | ||||||
the selector function's return value to your component. | ||||||
|
||||||
You can also use selector functions elsewhere in your Redux code as well. | ||||||
|
||||||
</Note> | ||||||
|
||||||
Open up `App.js`, and rewrite it to look like this: | ||||||
|
||||||
```js {2,5-7,10,14} | ||||||
import React from 'react' | ||||||
import { useSelector } from 'react-redux' | ||||||
import './styles.css' | ||||||
|
||||||
function selectHelloText(state) { | ||||||
return state | ||||||
} | ||||||
|
||||||
export default function App() { | ||||||
const helloText = useSelector(selectHelloText) | ||||||
|
||||||
return ( | ||||||
<div className="App"> | ||||||
<h1>{helloText}</h1> | ||||||
</div> | ||||||
) | ||||||
} | ||||||
``` | ||||||
|
||||||
We import the `useSelector` function from React-Redux, and then create a function called `selectHelloText`. It receives whatever state is in the Redux | ||||||
store as an argument. For now, we'll just return that entire state value. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've seen beginners frequently return the entire state when they don't need to in |
||||||
|
||||||
Inside the component, we call `useSelector` and pass in `selectHelloText`. When `useSelector` runs, it will call our selector function with the store | ||||||
state, and pass the return value to our component. | ||||||
|
||||||
Finally, we can put the text value into the header of our `<App>` component... and there it is! | ||||||
|
||||||
**You should now see the words "Hello Redux" on screen. Congratulations! You've set up Redux in your app.** | ||||||
|
||||||
Now that the setup is complete, we can start building the actual application logic. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we link to external resources here? In case the end user doesn't know these pre-reqs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, I'm just trying to get a list in place for now.