Skip to content
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

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/components/DetailedExplanation.js
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>
)
}
9 changes: 9 additions & 0 deletions docs/components/Note.js
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>
}
3 changes: 3 additions & 0 deletions docs/components/TestComponent.js
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>
337 changes: 337 additions & 0 deletions docs/introduction/QuickStart.mdx
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.
Comment on lines +29 to +33
Copy link

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.

Copy link
Contributor Author

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.


</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.
Copy link

Choose a reason for hiding this comment

The 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 helps you to write code that is testable, and helps you to understand when, where, why, and how the data in your application has changed.


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>
Copy link
Contributor

Choose a reason for hiding this comment

The 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.
Copy link

Choose a reason for hiding this comment

The 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
Copy link

Choose a reason for hiding this comment

The 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.
Copy link

Choose a reason for hiding this comment

The 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`.
Copy link

Choose a reason for hiding this comment

The 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.

Copy link

Choose a reason for hiding this comment

The 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:

  • help a person who already knows React feel grounded, adding new knowledge on top of old
  • help a person who has never seen React realize that they should go learn that first (provide a link to official tutorial) and that Redux builds on top of React

<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_**.

Copy link

Choose a reason for hiding this comment

The 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A **_reducer_** is a function that know how to calculate a new state value when asked. A Redux store requires a single reducer function
A **_reducer_** is a function that knows how to calculate a new state value when asked. A Redux store requires a single reducer function

Choose a reason for hiding this comment

The 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.
Copy link

Choose a reason for hiding this comment

The 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.
Copy link

Choose a reason for hiding this comment

The 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.
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link

Choose a reason for hiding this comment

The 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".

Copy link
Contributor Author

@markerikson markerikson Jan 23, 2020

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

@markerikson markerikson Jan 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intent is to have the first step simply be () => "Hello Redux" + const helloText = useSelector(state => state), and get that to show up on screen instead of the initial text in <App>. That gives them some immediate success in seeing something visible change on the page. Then, once they've seen the initial connection sequence, we can move on to filling out actual app logic.


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
Copy link

Choose a reason for hiding this comment

The 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

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link

@bpas247 bpas247 Jan 10, 2020

Choose a reason for hiding this comment

The 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 😃

Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link

Choose a reason for hiding this comment

The 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.
Copy link

Choose a reason for hiding this comment

The 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.
Copy link

Choose a reason for hiding this comment

The 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.
Copy link
Contributor

@nickserv nickserv Jan 20, 2020

Choose a reason for hiding this comment

The 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 mapStateToProps, causing unnecessary rerenders and defeating the purpose of this API. I understand that there's just one value in the store in this case, but I think we should at least note that only the state the component needs should be returned, as Redux optimizes rerenders based on the result. Also would help to mention that selectors getting the same data should be extracted into functions so they can be shared across components or even other selectors.


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.
Loading