├── .editorconfig ├── README.md ├── netlify.toml └── website ├── .gitignore ├── .prettierignore ├── .prettierrc.cjs ├── .yarn └── releases │ └── yarn-3.2.0.cjs ├── .yarnrc.yml ├── README.md ├── _redirects ├── babel.config.js ├── docs ├── common-mistakes │ └── common-mistakes.md ├── data-fetching-caching │ └── overview.mdx ├── glossary │ └── glossary.md ├── how-to │ └── how-to.md ├── state-management │ ├── mobx.mdx │ ├── overview.mdx │ ├── poimandres.mdx │ ├── react-state.mdx │ ├── redux.mdx │ └── xstate.mdx ├── styling │ ├── css-modules.mdx │ ├── css-preprocessors.mdx │ ├── emotion.mdx │ ├── inline-styles.mdx │ ├── overview.mdx │ ├── plain-css.mdx │ ├── styled-components.mdx │ └── styling-example.png └── use-cases │ ├── choosing-library-for-existing-project.md │ ├── starting-a-new-project.md │ └── starting-with-react.md ├── docusaurus.config.js ├── package.json ├── sidebars.js ├── src ├── css │ └── custom.css └── pages │ ├── index.js │ └── styles.module.css ├── static ├── .nojekyll └── img │ ├── favicon.ico │ ├── logo.svg │ ├── undraw_docusaurus_mountain.svg │ ├── undraw_docusaurus_react.svg │ └── undraw_docusaurus_tree.svg └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Community Tools and Practices Cheatsheet 2 | 3 | This is a placeholder for an idea: (refs: https://twitter.com/acemarke/status/1365834578087333895, https://twitter.com/acemarke/status/1365888195070681092): 4 | 5 | > it feels like there maybe needs to be more of a community effort to build up some kind of a centralized "best practices" site, perhaps similar to the React+TS CheatSheet ( https://github.com/typescript-cheatsheets/react ) 6 | > what if the community collaborated on putting together a centralized list of what the major options are in different categories, and when it might make sense to use them? 7 | > Obviously this could easily devolve into "NO, YOU SHOULD BE USING TOOL X INSTEAD OF TOOL Y", or "WHY ISN'T MY LIB WITH 27 STARS LISTED?". There'd need to be both curation and friendly cooperation from experts within the community in this. 8 | > Example, state management. The main options by usage % are plain React state, Redux, MobX, XState. Those overlap with data fetching libs like Apollo, React Query, and SWR. What if each lib submitted a page saying "here's our tool, what it solves, and when you might use it" 9 | > Similarly, styling. Major options are inline styles, plain CSS, CSS Modules, and CSS-in-JS approaches. Have some pages that detail what those options are, pros/cons, and why you might consider each approach. Not flat-out saying "use X or Y". Just "here's options and use cases" 10 | > One more: how do you pick between CRA, Next, Gatsby, or something like a Snowpack or Vite, to build a React app? When does it make sense to use any of those? Having a list of the major options and tradeoffs involved would be valuable. 11 | > Stackshare and Slant are _sorta_ along the lines of what I'm describing, although I'm picturing something much more text-based and involving descriptions, examples, and use cases. 12 | > I'm not saying any of this would be easy, and there'd be a lot of wrangling over how to format and present this info. also, not all would be "competing libs". like, `fetch` vs `axios` vs `redaxios` vs your own fetch wrapper 13 | 14 | So, this is me sorta putting my money where my mouth is, and creating a repo to start this. 15 | 16 | ## Initial Planning Discussion 17 | 18 | see [**Discussion #1 - Initial RFC: Scope and Goals**](https://github.com/markerikson/react-community-tools-practices-cheatsheet/discussions/1) for discussion of what this project should actually involve and how we might make it a reality. 19 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "website" 3 | publish = "build" 4 | command = "yarn build && cp _redirects ./build" 5 | 6 | [build.environment] 7 | NODE_VERSION = "16" 8 | YARN_VERSION = "1.22.18" 9 | YARN_FLAGS = "--immutable" -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | # Yarn 23 | .pnp.* 24 | .yarn/* 25 | !.yarn/patches 26 | !.yarn/plugins 27 | !.yarn/releases 28 | !.yarn/sdks 29 | !.yarn/versions -------------------------------------------------------------------------------- /website/.prettierignore: -------------------------------------------------------------------------------- 1 | .yarn/ 2 | .docusaurus/ -------------------------------------------------------------------------------- /website/.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | singleQuote: true, 3 | }; 4 | -------------------------------------------------------------------------------- /website/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | yarnPath: .yarn/releases/yarn-3.2.0.cjs 2 | 3 | nodeLinker: node-modules 4 | -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator. 4 | 5 | ## Installation 6 | 7 | ```console 8 | yarn install 9 | ``` 10 | 11 | ## Local Development 12 | 13 | ```console 14 | yarn start 15 | ``` 16 | 17 | This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ## Build 20 | 21 | ```console 22 | yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ## Deployment 28 | 29 | ```console 30 | GIT_USER= USE_SSH=true yarn deploy 31 | ``` 32 | 33 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 34 | -------------------------------------------------------------------------------- /website/_redirects: -------------------------------------------------------------------------------- 1 | # Empty redirects file for now -------------------------------------------------------------------------------- /website/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /website/docs/common-mistakes/common-mistakes.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: common-mistakes 3 | title: Common Mistakes 4 | sidebar_label: Common Mistakes 5 | --- 6 | 7 | ## Maintaining state that could be derived 8 | 9 | It can be pretty easy to find yourself maintaining several pieces of related state. Take the following code as an example: 10 | 11 | ```js 12 | const [dateOfBirth, setDateOBirth] = useState(null); 13 | const [ageInYears, setAgeInYears] = useState(null); 14 | const [daysUntilBirthday, setDaysUntilBirthday] = useState(null); 15 | 16 | useEffect(() => { 17 | setAgeInYears(getAgeInYears(dateOfBirth)); 18 | setDaysUntilBirthday(getDaysUntilBirthday(dateOfBirth)); 19 | }, [dateOfBirth]); 20 | ``` 21 | 22 | Based on the user's date of birth, we want to find out their age in years and how many days there are until their next birthday. It seems natural to watch the value of `dateOfBirth` and set the other pieces of state based on that. However, it may become hard to follow how the state is updated as the code becomes more complex. Especially if we call `setAgeInYears` or `setDaysUntilBirthday` in multiple places. We can express it more simply as: 23 | 24 | ```js 25 | const [dateOfBirth, setDateOBirth] = useState(null); 26 | const ageInYears = getAgeInYears(dateOfBirth); 27 | const daysUntilBirthday = getDaysUntilBirthday(dateOfBirth); 28 | ``` 29 | 30 | We can call `getAgeInYears` and `getDaysUntilBirthday` on each render. We know we will have the latest value for `dateOfBirth`, removing the need for the `useEffect`. We avoid any potential bugs related by deriving the state directly. We also don't need to write any synchronization code. 31 | 32 | You might be wondering, "What if it's very costly to calculate these derived state values? Won't this cause performance issues in my component?" which is a valid concern. However, in most cases, the values can be derived quickly, which won't impact performance. If you know a calculation will be costly or see performance issues, you can use the `useMemo` hook to run the calculations only when `dateOfBirth` updates. 33 | 34 | ```js 35 | const [dateOfBirth, setDateOBirth] = useState(null); 36 | const ageInYears = useMemo(() => getAgeInYears(dateOfBirth), [dateOfBirth]); 37 | const daysUntilBirthday = useMemo( 38 | () => getDaysUntilBirthday(dateOfBirth), 39 | [dateOfBirth] 40 | ); 41 | ``` 42 | 43 | In some ways, this is like using `useEffect` and setting the state when `dateOfBirth` changes. However, the values are derived directly from `dateOfBirth`, so we avoid the bugs and code that come with manually synchronizing the state. 44 | 45 | :::caution 46 | 47 | Remember that `useMemo` is an optimization for when a value is costly to calculate. You do not need to use it for every derived value, and using it unnecessarily could hurt performance. So don't optimize prematurely and measure before and after the optimization to ensure it provides value. [This article explores these optimizations and how they can be harmful](https://kentcdodds.com/blog/usememo-and-usecallback). 48 | 49 | ::: 50 | -------------------------------------------------------------------------------- /website/docs/data-fetching-caching/overview.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: overview 3 | title: 'Data Fetching and Caching: Overview' 4 | sidebar_label: 'Data Fetching and Caching: Overview' 5 | --- 6 | -------------------------------------------------------------------------------- /website/docs/glossary/glossary.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: glossary 3 | title: Glossary 4 | sidebar_label: Glossary 5 | --- 6 | -------------------------------------------------------------------------------- /website/docs/how-to/how-to.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: how-to 3 | title: How To.. 4 | sidebar_label: How To.. 5 | --- 6 | -------------------------------------------------------------------------------- /website/docs/state-management/mobx.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: mobx 3 | title: 'Mobx' 4 | sidebar_label: 'Mobx' 5 | --- 6 | 7 | ## Description 8 | 9 | Mobx applies concepts from Functional Reactive Programming and Object-Oriented design to automatically track changes to state and propagate updates. Mobx lets you create individual "store" classes and mark specific fields as "observable", then mark React components and other logic as "observers". You can directly modify those observables fields in your code, and Mox will transparently update any observer code that depends on those fields. 10 | 11 | ## Purpose and Use Cases 12 | 13 | TBD 14 | 15 | ## Tradeoffs 16 | 17 | TBD 18 | 19 | ## When Should I Consider Using This? 20 | 21 | TBD 22 | 23 | ## Further Information 24 | -------------------------------------------------------------------------------- /website/docs/state-management/overview.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: overview 3 | title: 'State Management: Overview' 4 | sidebar_label: 'State Management: Overview' 5 | --- 6 | 7 | ## What is State Management? 8 | 9 | **"State" is any data that describes the current behavior of an application**. This could include values like "a list of objects fetched from the server", "which item is currently selected", "name of the currently logged-in user", and "is this modal open?". 10 | 11 | **"State Management" is the process of dealing with changes to state over time**. This means having ways to: 12 | 13 | - _store_ an initial value 14 | - _read_ the current value 15 | - _update_ a value 16 | 17 | There's also typically a way to be notified when the current value has changed. 18 | 19 | React applications decide what UI to render based on the current state values. Because of this, understanding when and how to use different techniques for managing state is a key skill for all React developers, as is the ability to decide where a given piece of state should live. 20 | 21 | ## Types of State 22 | 23 | There's several ways we could categorize different kinds of state in a client-side application. One set of categories might be: 24 | 25 | - **Data**: values that relate to specific features or business logic in the application (such as a list of todos) 26 | - **Control/UI state**: values related to how the user is interacting with the app (such as which todo item is currently selected) 27 | - **Session state**: values related to the current user (such as a username or profile) 28 | - **Communication state**: values that describe requests to other servers (such as a "loading" value) 29 | - **Location state**: values that are in the current browser URL and HTML `history` object (such as the domain, the path, query parameters, and client routing navigation history) 30 | 31 | Another set of categories might be: 32 | 33 | - **Local client state**: values that are scoped directly to a single component or its descendants 34 | - **Global client state**: values that are broadly needed in many places throughout an application 35 | - **Server state**: values that are fetched from a server via an API and cached on the client 36 | 37 | ## State Management Tools 38 | 39 | Because state management is such a vital part of writing React applications, the React community has developed many different tools and patterns for working with state. 40 | 41 | ### React State Management 42 | 43 | React itself has several built-in APIs for managing state, including the `useState` and `useReducer` hooks for managing state inside of React components. It also has a Context API to help with passing data down the component tree. In many cases, React's built-in state management tools are all you'll need to build applications. 44 | 45 | Some common patterns for React state management are: 46 | 47 | - **"Lifting state up"**: since data flows down the tree as props, sibling components can't share data directly. By putting state in their nearest common ancestor component, the child components can all receive that data via props or context. 48 | - **"Colocating state"**: some state may only be needed in a certain subtree of the application. It's best to keep the state stored as close as possible to where it's actually needed, which helps optimize rendering behavior. 49 | - **"Prop drilling"**: passing values from parents as props through many levels of nested child components, explicitly 50 | - **"Providers"**: React's Context API allows rendering a `` component, and nested children can read the value from that context directly without having to prop-drill. A component whose job is to store state and render a `` is also often referred to as a "provider component". 51 | 52 | ### External State Management 53 | 54 | The React community has created many different libraries to help manage state outside of React components. Some of the most popular libraries are: 55 | 56 | - [Redux](./redux.mdx): focuses on making state updates predictable and traceable, with inspiration from the "Flux Architecture" pattern and Functional Programming principles. It relies on separating descriptions of "what happened", called "actions", from the logic that decides how state should be updated, called "reducer functions". Redux centralizes global application state into a single "store", and provides browser DevTools to view the history of state changes over time. 57 | - [Mobx](./mobx.mdx): applies concepts from Functional Reactive Programming and Object-Oriented design to automatically track changes to state and propagate updates. Mobx lets you create individual "store" classes and mark specific fields as "observable", then mark React components and other logic as "observers". You can directly modify those observables fields in your code, and Mobx will transparently update any observer code that depends on those fields. 58 | - [XState](./xstate.mdx): builds on time-tested Computer Science patterns for defining and executing Finite State Machines and Statecharts, including interacting between those machines using the Actor Model. XState enables defining specific known possible states for a system, how different events cause transitions between those states, and what side effects are executed as a result. It has the ability to visualize state machines and their transitions graphically. 59 | 60 | ## Data Fetching and Caching 61 | 62 | There is overlap between the ideas of "managing state" and "caching fetched data from the server". For example, you can use a state management tool like Mobx or Redux to track loading state and cache the fetched data, although they are not purpose-built for that use case. There are also tools that _are_ specifically designed to abstract the use case of fetching data, caching it, and managing the loading state and cached data internally without needing to write that code yourself. 63 | 64 | See [Data Fetching and Caching: Overview](../data-fetching-caching/overview.mdx) for discussion of concepts and tools for that category. 65 | 66 | ## Further Information 67 | 68 | - [The 5 Types of React Application State](http://jamesknelson.com/5-types-react-application-state/) 69 | -------------------------------------------------------------------------------- /website/docs/state-management/poimandres.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: poimandres 3 | title: 'Zustand, Jotai, Valtio' 4 | sidebar_label: 'Zustand, Jotai, Valtio' 5 | --- 6 | 7 | [Poimandres](https://github.com/pmndrs) is a developer collective and they host various OSS projects. Some of famous projects are [react-spring](https://github.com/pmndrs/react-spring) and [react-three-fiber](https://github.com/pmndrs/react-three-fiber). They also provide three popular state managers, namely [zustand](https://zustand-demo.pmnd.rs), [jotai](https://jotai.org), and [valtio](https://valtio.pmnd.rs). This document introduces those three state managers and discuss their features. 8 | Three micro-state management libraries from a single GitHub organization may sound counter-intuitive, but they are in different styles. 9 | 10 | # Zustand 11 | 12 | ## Description 13 | 14 | Zustand is a tiny library primarily designed to create module state for React. It's based on an immutable update model, in which state objects can't be modified but always have to be newly created. Render optimization is done manually using selectors. It has a straightforward and yet powerful store creator interface. 15 | 16 | ## Purpose and Use Cases 17 | 18 | Zustand primarily designed for module state, which means you define this store in a module and export it. 19 | 20 | - Zustand is very small. So, it's good for a lightweight solution. For example, some apps use react-query for server state, and such apps only need a small global state. Zustand would be a best fit for such small use cases. 21 | - Immutable state model is the same as what React itself is based on. There would be less mental model switch between React state and zustand global state. So, it would be good for developers who are used to React's useState. 22 | - Unopinionated. The library has less restrictions, and very open. It's developers responsibility to organize well. It would be best if developers need flexibility with responsibility. 23 | 24 | ## Tradeoffs 25 | 26 | Zustand's render optimization with selector functions is also based on immutability – that is, if a selector function returns the same object referentially (or value), it assumes that the object is not changed and avoids re-rendering. 27 | 28 | having the same model as React gives us a huge benefit in terms of library simplicity and its small bundle size. 29 | 30 | On the other hand, a limitation of Zustand is its manual render optimization with selectors. It requires that we understand object referential equality and the code for selectors tends to require more boilerplate code. 31 | 32 | ## When Should I Consider Using This? 33 | 34 | Zustand – or any other libraries with this approach – is a simple addition to the React principle. It's a good recommendation if you need a library with a small bundle size, if you are familiar with referential equality and memoization, or you prefer manual render optimization. 35 | 36 | ## Example 37 | 38 | ```tsx 39 | import create from 'zustand'; 40 | 41 | type Store = { 42 | count: number; 43 | unusedCount: number; 44 | add: (n: number) => void; 45 | }; 46 | 47 | const useStore = create((set) => ({ 48 | count: 0, 49 | unusedCount: 0, 50 | add: (n) => set((prev) => ({ count: prev.count + n })), 51 | })); 52 | 53 | const Counter = () => { 54 | const count = useStore((state) => state.count); 55 | const add = useStore((state) => state.add); 56 | return ( 57 |
58 | {count} 59 |
60 | ); 61 | }; 62 | 63 | export default Counter; 64 | ``` 65 | 66 | ## Differences between Zustand and Redux 67 | 68 | In some use cases, the developer experience can be similar in Zustand and Redux. Both are based on one-way data flow. In one-way data flow, we dispatch action, which represents a command to update a state, and after the state is updated with action, the new state is propagated to where it's needed. 69 | 70 | On the other hand, they differ in how to update states. Redux is based on reducers. While updating states with reducers is a strict method, it leads to more predictability. Zustand takes a flexible approach and it doesn't necessarily use reducers to update states. 71 | 72 | # Jotai 73 | 74 | ## Description 75 | 76 | Jotai is a small library for the global state. It's modeled after useState/useReducer and with what are called atoms, which are usually small pieces of state. Unlike Zustand, it is a component state, and like Zustand, it is an immutable update model. 77 | 78 | ## Purpose and Use Cases 79 | 80 | The combination of Context and Subscription is the only way to have a React-oriented global state. If your requirement is Context without extra re-renders, this approach should be your choice. 81 | 82 | ## Tradeoffs 83 | 84 | There are two benefits when using Jotai, as follows: 85 | 86 | ### Syntax simplicity 87 | 88 | To understand syntax simplicity, let's look at the same counter example with Jotai. First, we need to import some functions from the Jotai library, as follows: 89 | 90 | ```jsx 91 | import { atom, useAtom } from 'jotai'; 92 | ``` 93 | 94 | The `atom` function and the `useAtom` hook are basic functions provided by Jotai. 95 | 96 | An `atom` represents a piece of a state. An `atom` is usually a small piece of state, and it is a minimum unit of triggering re-renders. The `atom` function creates a definition of an atom. The `atom` function takes one argument to specify an initial value, just as `useState` does. The following code is used to define a new atom: 97 | 98 | ```jsx 99 | const countAtom = atom(0); 100 | ``` 101 | 102 | Notice the similarity with `useState(0)`. `useAtom(countAtom)` returns the same tuple, `[count, setCount]`, 103 | as `useState(0)` does. 104 | 105 | ### Non-global state 106 | 107 | The second benefit of Jotai is a new capability—that is, non-global state. Atoms can be created and destroyed in the React component lifecycle. This is not possible with the multiple-Context approach, because adding a new state means adding a new `Provider` component. If you add a new component, all its child components will be remounted, throwing away their states. 108 | 109 | ### Derived atom 110 | 111 | The third benefit is derived atom. The atom function provided by library is very primitive, but it's also so flexible that you can combine multiple atoms to implement a functionality. Atoms are building block. By composing atoms based on other atoms, we can implement complicated logic. For example, we can create a new atom that is the sum of two other atoms. 112 | 113 | ## When Should I Consider Using This? 114 | 115 | The answer would be to use jotai for component-centric apps. 116 | 117 | With the component-centric approach, you would design components first. Some states can be locally defined in components with useState. Other states will be shared across components. For example, in a GUI intensive app, you want to control UI parts in sync, but they are far away in the component tree. 118 | 119 | ## Example 120 | 121 | ```tsx 122 | import { atom, useAtom } from 'jotai'; 123 | 124 | const countAtom = atom(0); 125 | const addCountAtom = atom(null, (_get, set, n: number) => { 126 | set(countAtom, (c) => c + n); 127 | }); 128 | 129 | const Counter = () => { 130 | const [count] = useAtom(countAtom); 131 | const [, add] = useAtom(addCountAtom); 132 | return ( 133 |
134 | {count} 135 |
136 | ); 137 | }; 138 | 139 | export default Counter; 140 | ``` 141 | 142 | ## Differences between Recoil and Jotai 143 | 144 | Jotai's API is highly inspired by Recoil. In the beginning, it's intentionally designed to help migration from Recoil to Jotai. The differences are as follows: 145 | 146 | - The biggest difference is the existence of the key string. One of the big motivations of developing Jotai is to omit the key string which let to better DX. Naming is a hard task in coding, especially because the key property has to be unique. 147 | 148 | - Another difference of Jotai is the provider-less mode in Jotai, which allows omission of the Provider component, is technically simple, but very developer-friendly to lower the mental barrier as regards using the library. 149 | 150 | # Valtio 151 | 152 | ## Description 153 | 154 | Valtio is yet another library for global state. Unlike Zustand and Jotai, it's based on the mutating update model. It's primarily for module states like Zustand. It utilizes proxies to get an immutable snapshot, which is required to integrate with React. 155 | 156 | ## Purpose and Use Cases 157 | 158 | The API is just JavaScript and everything works behind the scenes. It also leverages proxies to automatically optimize re-renders. It doesn't require a selector to control re-renders. The automatic render optimization is based on a technique called state usage tracking. Using state usage tracking, it can detect which part of the state is used, and it can let a component re-render only if the used part of the state is changed. In the end, developers need to write less code. 159 | 160 | ## Tradeoffs 161 | 162 | One big aspect is the mental model. We have two state-updating models. One is for immutable updates and the other for mutable updates. While JavaScript itself allows mutable updates, React is built around immutable states. Hence, if we mix the two models, we should be careful not to confuse ourselves. One possible solution would be to clearly separate the Valtio state and React state so that the mental model switch is reasonable. If it works, Valtio can fit in. Otherwise, maybe stick with immutable updates. The major benefit of mutable updates is we can use native JavaScript functions. 163 | 164 | On the other hand, a disadvantage of proxy-based render optimization can be less predictability. Proxies take care of render optimization behind the scenes and sometimes it's hard to debug the behavior. Some may prefer explicit selector-based hooks. In summary, there's no one-size-fits-all solution. It's up to developers to choose the solution that fits their needs. 165 | 166 | ## When Should I Consider Using This? 167 | 168 | the answer would be to use valtio for data-centric apps. 169 | 170 | The data-centric approach is you have data first regardless of React components. React components are used to represent those data. For example, in game development, it’s likely that you may have game state in advance to design components. You don’t want these data to be controlled by React lifecycle. 171 | 172 | ## Example 173 | 174 | ```tsx 175 | import { proxy } from 'valtio'; 176 | import { useProxy } from 'valtio/macro'; 177 | 178 | const state = proxy({ 179 | count: 0, 180 | unusedCount: 0, 181 | add: (n: number) => { 182 | state.count += n; 183 | }, 184 | }); 185 | 186 | const Counter = () => { 187 | useProxy(state); 188 | return ( 189 |
190 | {state.count} 191 |
192 | ); 193 | }; 194 | 195 | export default Counter; 196 | ``` 197 | 198 | ## Differences between Valtio and MobX 199 | 200 | Although the motivation is quite different, Valtio is often compared to [MobX](https://mobx.js.org). Usage-wise, there are some similarities in Valtio and MobX regarding their React binding. Both are based on mutable states and developers can directly mutate state, which results in similar usage. JavaScript is based on mutable objects, so the syntax of mutating an object is very natural and compact. This is a big win for mutable states compared to immutable states. 201 | 202 | On the other hand, there is a difference in how they optimize renders. For render optimization, while Valtio uses a hook, MobX React uses a higher-order component ([HoC](https://reactjs.org/docs/higher-order-components.html)). 203 | 204 | # Comparing Zustand, Jotai, and Valtio 205 | 206 | There is a philosophy that is common in the three libraries: their small API surfaces. All three libraries try their best to provide small API surfaces and let developers compose the APIs as they want. 207 | 208 | But then, what are the differences between the three libraries? 209 | 210 | There are two aspects: 211 | 212 | - **Where does the state reside?** In React, there are two approaches. One is the module state, and the other is the component state. A module state is a state that is created at the module level and doesn't belong to React. A component state is a state that is created in React component life cycles and controlled by React. Zustand and Valtio are designed for module states. On the other hand, Jotai is designed for component states. For example, consider Jotai atoms. The following is a definition of `countAtom`: 213 | 214 | ```jsx 215 | const countAtom = atom(0); 216 | ``` 217 | 218 | - This `countAtom` variable holds a config object, and it doesn't hold a value. The atom values are stored in a `Provider` component. Hence, `countAtom` can be reused for multiple components. Implementing the same behavior is tricky with module states. With Zustand and Valtio, we would end up using React Context. On the other hand, accessing component states from outside React is technically not possible. We'll likely need some sort of module state to connect to the component states. Whether we use module states or component states depends on the app requirements. Usually, using either module states or component states for global states fulfills the app requirements, but in some rare cases, using both types of states may make sense. 219 | 220 | * **What is the state updating style?** There is a major difference between Zustand and Valtio. Zustand is based on the immutable state model, while Valtio is based on the mutable state model. The contract in the immutable state model is that objects cannot be changed once created. Suppose you have a state variable such as `state = { count: 0 }`. If you want to update the count in the immutable state model, you need to create a new object. Hence, incrementing the count by 1 should be `state = { count: state.count + 1 }`. In the mutable state mode, it could be `++state.count`. This is because JavaScript objects are mutable by nature. The benefit of the immutable model is that you can compare the object references to know whether anything has changed. It helps improve performance for large, nested objects. Because React is mostly based on the immutable model, Zustand with the same model has compatibility. Thus, Zustand is a very thin library. On the other hand, Valtio, with the mutable state model, requires filling the gap between the two models. In the end, Zustand and Valtio take different state updating styles. The mutable updating style is very handy, especially when an object is deeply nested. 221 | 222 | There are some minor differences among the three libraries, but what's important is the fact that they are based on different principles. If we were to choose one of them, we would need to see which principle fits well with our app requirements and our mental model. 223 | 224 | ## Further Information 225 | 226 | - [📚 Micro State Management with React Hooks](https://www.amazon.com/Micro-State-Management-React-Hooks-dp-1801812373/dp/1801812373/ref=mt_other?_encoding=UTF8&me=&qid=1643728846) 227 | - [Zustand GitHub repository](https://github.com/pmndrs/zustand) 228 | - [Zustand demo](https://zustand-demo.pmnd.rs/) 229 | - [Jotai GitHub repository](https://github.com/pmndrs/jotai) 230 | - [📚 Jotai documentation](https://jotai.org/docs/introduction) 231 | - [Valtio documentation ](https://github.com/pmndrs/valtio) 232 | - [📚 Valtio demo](https://valtio-demo.pmnd.rs/) 233 | - [When I Use Valtio and When I Use Jotai](https://blog.axlight.com/posts/when-i-use-valtio-and-when-i-use-jotai/) 234 | - [Daishi Kato's blog](https://blog.axlight.com/) 235 | -------------------------------------------------------------------------------- /website/docs/state-management/react-state.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: react-state 3 | title: 'React State' 4 | sidebar_label: 'React State' 5 | --- 6 | 7 | ## Description 8 | 9 | React itself has several built-in APIs for managing state, including the `useState` and `useReducer` hooks for managing state inside of React components. It also has a Context API to help with passing data down the component tree. In many cases, React's built-in state management tools are all you'll need to build applications. 10 | 11 | ## Purpose and Use Cases 12 | 13 | TBD 14 | 15 | ## Tradeoffs 16 | 17 | TBD 18 | 19 | ## When Should I Consider Using This? 20 | 21 | TBD 22 | 23 | ## Further Information 24 | -------------------------------------------------------------------------------- /website/docs/state-management/redux.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: redux 3 | title: 'Redux' 4 | sidebar_label: 'Redux' 5 | --- 6 | 7 | ## Description 8 | 9 | **Redux is a pattern and library for managing and updating application state, using events called "actions"**. It serves as a centralized store for state that needs to be used across your entire application, with rules ensuring that the state can only be updated in a predictable fashion. 10 | 11 | Redux focuses on making state updates predictable and traceable, with inspiration from the "Flux Architecture" pattern and Functional Programming principles. It relies on separating descriptions of "what happened", called "actions", from the logic that decides how state should be updated, called "reducer functions". Redux centralizes global application state into a single "store", and provides browser DevTools to view the history of state changes over time. 12 | 13 | ## Purpose and Use Cases 14 | 15 | **The primary purpose of Redux is to help you manage "global" state** — state that is needed across many parts of your application. 16 | 17 | **The patterns and tools provided by Redux make it easier to understand when, where, why, and how the state in your application is being updated, and how your application logic will behave when those changes occur**. Redux guides you towards writing code that is predictable and testable, which helps give you confidence that your application will work as expected. 18 | 19 | Because any component can access data that is being kept in the Redux store, it _can_ be used to avoid "prop-drilling". However, this is an added benefit, and not specifically the main reason to use Redux. 20 | 21 | ## Tradeoffs 22 | 23 | Redux asks you to write your code following specific patterns: 24 | 25 | - Application state should be described using plain JS objects and arrays 26 | - There must be a single Redux store that holds the application state 27 | - The store can only be updated by describing events that happen as plain "action" objects, and "dispatching" them to the store for processing 28 | - The logic for updating the store state must be written as "reducer" functions, which look at the current state and the action object to decide what the resulting new state should be. Reducer functions must be "pure", with no side effects, and must calculate the new state using immutable updates. 29 | 30 | This adds a level of indirection to the process of managing state. Because of this, Redux is not intended to be the shortest or fastest way to update state. 31 | 32 | However, the indirection of separating descriptions of "what happened" from the logic that determines "how the state should be updated" allows Redux to track how the state changed every time an action is dispatched. The Redux DevTools can then display the history of dispatched actions, the diff between states, and the complete state tree after each dispatched action. This makes it easier to understand how the application behaves as things change. This also enables Redux "middleware", which can inspect dispatched actions and run additional logic in response. 33 | 34 | Because Redux is a single store, all components that have subscribed to reading state updates have to re-run comparison checks after every dispatched action, to see if the data needed by that specific component has changed. This does require that users carefully define how each component reads data from the Redux store, including use of "memoized" selector functions and semi-manual optimizations. It also means that it's generally not a good idea to put most UI state values like "is this dropdown open?" or form state into the Redux store. 35 | 36 | Redux is UI-agnostic and can be used with any UI layer, including React, Angular, Vue, and vanilla JS. 37 | 38 | ## Packages 39 | 40 | The core [Redux](https://redux.js.org/) library provides a minimal set of APIs for creating a Redux store. 41 | 42 | The official [Redux Toolkit](https://redux-toolkit.js.org) package adds additional APIs for standard Redux use cases like setting up a store with good defaults, catching common mistakes in development, and creating Redux reducers with simpler logic than writing immutable updates by hand. 43 | 44 | [React-Redux](https://react-redux.js.org) is the official bindings layer that lets React components interact with a Redux store by reading state values and dispatching actions. 45 | 46 | Redux has a thriving ecosystem of additional addons, including middleware for writing side effects and async logic with different syntaxes, tools for persisting store state, and much more. 47 | 48 | ## When Should I Consider Using This? 49 | 50 | Redux helps you deal with shared state management, but there are more concepts to learn, and more code to write. It also adds some indirection to your code, and asks you to follow certain restrictions. It's a trade-off between short term and long term productivity. 51 | 52 | **Redux is more useful when**: 53 | 54 | - You have large amounts of application state that are needed in many places in the app 55 | - The app state is updated semi-frequently 56 | - The logic to update that state may be complex 57 | - The app has a medium or large-sized codebase, and might be worked on by many people 58 | - You want to see a history of changes to your application state over time 59 | - You want to write as much of your logic as possible separate from the UI layer 60 | 61 | **You should probably avoid using Redux if**: 62 | 63 | - You prefer an Object-Oriented approach instead of a Functional Programming approach 64 | - Your app mostly depends on fetching and caching data from the server and you are using another tool to manage that cached server state 65 | - You want UI updates and data dependencies to be as automatic as possible, with minimal manual optimizations 66 | - You prefer writing logic that directly applies state updates with minimal indirection 67 | - Most of the data in your application is only needed by specific subsections of the component tree, with little "global" state 68 | - You want to stick with built-in React APIs and avoid additional third-party dependencies 69 | 70 | ## Further Information 71 | 72 | - [When (and when not) to reach for Redux](https://changelog.com/posts/when-and-when-not-to-reach-for-redux) 73 | - [The Tao of Redux, Part 1 - Implementation and Intent](https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-1/) 74 | - [Redux FAQ: When should I use Redux?](https://redux.js.org/faq/general#when-should-i-use-redux) 75 | - [You Might Not Need Redux](https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367) 76 | -------------------------------------------------------------------------------- /website/docs/state-management/xstate.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: xstate 3 | title: 'XState' 4 | sidebar_label: 'XState' 5 | --- 6 | 7 | ## Description 8 | 9 | XState is a state orchestration library for implementing finite-state machines, statecharts, and the actor model in any application. XState enables defining specific known possible "finite-states" (e.g. modes, statuses, behaviors) for any part of a system, how different events cause transitions between those states, and which actions (side-effects) are executed as a result. It has the ability to visualize state machines and their transitions graphically, and in real-time. 10 | 11 | ## Purpose and Use Cases 12 | 13 | The purpose of XState is to express application logic, including states, transitions, and actions (effects) in a visually understandable way. This is accomplished by using statecharts (extended finite-state machines) and the actor model. Complex logic can be declaratively expressed with XState such that the implementation details for guards, actions, and invocations are configurable, making the created statecharts reusable for different use-cases, in different components, and even for different frameworks and languages. 14 | 15 | By making logic finite-state first instead of event-first and state transitions explicit, statecharts with XState prevent impossible states and transitions. It also eliminates the need for defensive logic, since implicit "handle the event this way _only if_ in this state" logic is instead a natural part of the state machine model. 16 | 17 | XState is primarily used for expressing complex logic, and has many use-cases: 18 | 19 | - Expressing status, such as for data fetching, processes, workflows 20 | - Declarative action (effect) orchestration with transitions 21 | - Component and application modes, and restricting which events will have an effect in certain modes 22 | - Multi-step forms and "wizards" 23 | - Chatbot-like applications 24 | - Multi-part async transformations 25 | - Model-based testing 26 | - Reusing logic in a highly configurable way 27 | - Autogenerating diagrams & documentation 28 | - Framework-independent logic 29 | - Game development 30 | - Prototyping logic (specifying implementation later) 31 | - Automation 32 | 33 | ## Tradeoffs 34 | 35 | The main trade-off is the learning curve. To be highly productive with XState, it is good (but not completely necessary) to understand the concepts of: 36 | 37 | - Event-driven software 38 | - Finite-state machines 39 | - Statecharts 40 | - The actor model 41 | 42 | Expressing simpler state management logic in XState can sometimes be a little more verbose than using "direct-manipulation" techniques. This is because XState scales for complexity, and makes the trade-off of allowing highly complex app logic to be represented clearly and robustly rather than making general use-cases "easy". 43 | 44 | XState also eschews the idea of a single global atomic store, and instead encourages smaller "stores" (actors) that can communicate with each other. This allows it to be consistently used anywhere, from the component level to the "global" application level, but with the trade-off that communication needs to be coordinated with events, which can add some complexity. 45 | 46 | ## When Should I Consider Using This? 47 | 48 | You should consider using XState once any part of your app reaches a point where deciphering the logic becomes hard to understand. Signs include: 49 | 50 | - Multiple lines of logic in event handlers 51 | - Multiple coordinated boolean variables for expressing some mode or status 52 | - Complicated if-statements with confusing predicates 53 | - Effects that are difficult to synchronize with state 54 | - Unhandled edge-cases 55 | - Impossible states present, or defensive logic for handling specific impossible states 56 | - Inability to clearly express what can happen at any point of time (events, states, transitions) 57 | - Difficulty in comprehensively testing logic, including effects 58 | - Rigid, "baked-in" logic that is difficult to share, reuse, or extract from app code 59 | - Necessity to document and/or diagram app logic without artifacts going stale 60 | 61 | ## Further Information 62 | 63 | - [XState GitHub repository](https://github.com/statelyai/xstate) 64 | - [📚 XState documentation](https://xstate.js.org/docs/) 65 | - [Stately visualizer](https://stately.ai/viz) 66 | - [Stately editor](https://stately.ai/editor) 67 | -------------------------------------------------------------------------------- /website/docs/styling/css-modules.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: css-modules 3 | title: 'CSS Modules' 4 | sidebar_label: 'CSS Modules' 5 | --- 6 | 7 | ## Description 8 | 9 | A [CSS Module](https://github.com/css-modules/css-modules) is a CSS file where class names are locally scoped. Though the name may make CSS Modules sound like an official spec that extends the CSS language, this is not the case — CSS Modules were invented by members of the community and must be compiled to normal CSS before being served on the web. 10 | 11 | To begin using CSS Modules, create a file with the `.module.css` extension and add a class name selector: 12 | 13 | ```css title="App.module.css" 14 | .appContainer { 15 | background-color: #fafafa; 16 | font-family: sans-serif; 17 | } 18 | ``` 19 | 20 | Then import the CSS module in your JavaScript code and attach the class name to an element: 21 | 22 | ```jsx title="App.jsx" 23 | import styles from './App.module.css'; 24 | 25 | export function App() { 26 | return
Content here
; 27 | } 28 | ``` 29 | 30 | Some things to note about the above example: 31 | 32 | - We used a camelCase class name — camel case is preferable when using CSS Modules since the class names need to be accessed from JavaScript. 33 | - The CSS Module for `App.jsx` is called `App.module.css`. This is a common pattern when using CSS Modules: for each `[component].jsx`, you create a `[component].module.css` file that contains the styles for that component. 34 | 35 | ## Purpose and Use Cases 36 | 37 | A common pitfall when using plain CSS (with or without a preprocessor) is that same class name may be accidentally used for two different purposes. For example, imagine `page1.css` defines styles for an error alert like this: 38 | 39 | ```css title="page1.css" 40 | .error { 41 | display: block; 42 | padding: 1rem; 43 | background-color: #faf38f; 44 | border-color: 1px solid red; 45 | font-weight: bold; 46 | } 47 | ``` 48 | 49 | You are working on page 2 and wish to add a small bottom margin to an error label. If you don't remember that `.error` styles are also defined in `page1.css`, you may accidentally reuse the `error` class name and write something like this: 50 | 51 | ```css title="page2.css" 52 | .error { 53 | margin-bottom: 0.5rem; 54 | } 55 | ``` 56 | 57 | If `page1.css` and `page2.css` are compiled into a single CSS bundle which is included in the `` of your single page app's HTML, page 2's simple error label will end up with a large padding, a background color, and a border, since these styles were defined in `page1.css`. That isn't what we wanted! We really want `page1.css` to only apply to page 1, and `page2.css` to only apply to page 2. 58 | 59 | CSS Modules fixes this problem by making all class names locally scoped. It does this by transforming your class names at build time. In the example above, the module loader would transform the class names like this: 60 | 61 | ```text 62 | error (from page1.css) ➙ _src_page1_module__error 63 | error (from page2.css) ➙ _src_page2_module__error 64 | ``` 65 | 66 | While the exact transformation algorithm used may vary, the end result is the same: there will never be a collision between two CSS classes defined in different files. 67 | 68 | When you import a CSS Module from a JavaScript file, you get an object which maps the human-readable class names to transformed class names. For example, this code, 69 | 70 | ```js 71 | import styles from 'page1.module.css'; 72 | console.log(styles); 73 | ``` 74 | 75 | will print 76 | 77 | ```text 78 | { error: '_src_page1_module__error' } 79 | ``` 80 | 81 | to the console. 82 | 83 | ## Tradeoffs 84 | 85 | There are no major tradeoffs when using CSS Modules instead of plain CSS, though you need to make sure you are using a bundler which supports CSS Modules. CSS Modules are supported out of the box when using Webpack's `css-loader`, Create React App, or Next.js. 86 | 87 | CSS Modules are potentially less convenient than plain CSS if you _want_ to attach styles to the same class name in different files. You can achieve this behavior by using the `:global` directive as described [here](https://github.com/css-modules/css-modules#exceptions). 88 | 89 | CSS Modules can be seen as a middle ground between plain CSS and a full-fledged CSS-in-JS library. Like plain CSS, CSS Modules have no runtime overhead since they are transformed to plain CSS at compile time. Like CSS-in-JS libraries, CSS Modules offer locally-scoped styles. That said, CSS-in-JS provides tighter integration between your CSS and JavaScript code: 90 | 91 | - With CSS-in-JS, you can define a React component and its styles in a single `.jsx` file, whereas with CSS Modules, you need both a `.jsx` file and a `.module.css` file. 92 | - Styles defined in via CSS-in-JS have full access to JavaScript variables (e.g. color constants), while CSS Modules do not. 93 | 94 | ## When Should I Consider Using This? 95 | 96 | - You are working on a medium or large application, since class name collisions are more likely to occur in larger codebases. 97 | - You want locally-scoped class names, without the larger bundle size and runtime performance costs that come with using a CSS-in-JS library. 98 | - You are using a CSS preprocessor like Sass. Preprocessors and CSS modules can be used together. 99 | 100 | ## Further Information 101 | 102 | - [CSS Module](https://github.com/css-modules/css-modules) 103 | - [How to configure CSS Modules for Webpack](https://blog.logrocket.com/how-to-configure-css-modules-webpack/) 104 | 105 | ## Example 106 | 107 | This example shows how to create the following component using React and CSS Modules. 108 | 109 | ![A card component with a button](styling-example.png) 110 | 111 | In your `.jsx` file, import from the `.module.css` file, which we'll add in a bit. Then write the JSX code and use the `styles` object when setting the `className` for each element. 112 | 113 | ```jsx title="Card.jsx" 114 | import styles from './Card.module.css'; 115 | 116 | export function Card() { 117 | return ( 118 |
119 |
120 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 121 |
122 | 123 |
124 | ); 125 | } 126 | ``` 127 | 128 | Next, we add the CSS Module: 129 | 130 | ```css title="Card.module.css" 131 | .card { 132 | border: 1px solid #ccc; 133 | border-radius: 0.5rem; 134 | padding: 1rem; 135 | max-width: 200px; 136 | box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); 137 | } 138 | 139 | .card .cardContent { 140 | margin-bottom: 1rem; 141 | } 142 | 143 | button { 144 | border: 0; 145 | background-color: #0d6efd; 146 | color: white; 147 | padding: 0.5rem; 148 | font-size: 1rem; 149 | border-radius: 0.25rem; 150 | width: 100%; 151 | } 152 | 153 | button:hover { 154 | background-color: #025ce3; 155 | } 156 | ``` 157 | 158 | And that's it! If properly configured, your bundler will transform the class names in the CSS Module so that your styles are locally scoped. 159 | -------------------------------------------------------------------------------- /website/docs/styling/css-preprocessors.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: css-preprocessors 3 | title: 'CSS Preprocessors' 4 | sidebar_label: 'CSS Preprocessors' 5 | --- 6 | 7 | ## Description 8 | 9 | CSS preprocessors extend the CSS language with powerful features like compile-time variables, nesting, inheritance, and mixins. The CSS preprocessor transforms these language extensions into plain CSS during your build step. The main CSS preprocessors are 10 | 11 | - [Sass](https://sass-lang.com/) 12 | - [LESS](https://lesscss.org/) 13 | - [stylus](https://stylus-lang.com/) 14 | 15 | with Sass being the most popular. 16 | 17 | The advanced language features provided by CSS preprocessors enable you to write cleaner code with less duplication. Here's an example from the [Sass documentation](https://sass-lang.com/guide) that shows how mixins can keep your code [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself): 18 | 19 | ```scss title="styles.scss" 20 | @mixin theme($theme: DarkGray) { 21 | background: $theme; 22 | box-shadow: 0 0 1px rgba($theme, 0.25); 23 | color: #fff; 24 | } 25 | 26 | .info { 27 | @include theme; 28 | } 29 | .alert { 30 | @include theme($theme: DarkRed); 31 | } 32 | .success { 33 | @include theme($theme: DarkGreen); 34 | } 35 | ``` 36 | 37 | Sass will compile the above code to the following plain CSS: 38 | 39 | ```css title="styles.css" 40 | .info { 41 | background: DarkGray; 42 | box-shadow: 0 0 1px rgba(169, 169, 169, 0.25); 43 | color: #fff; 44 | } 45 | 46 | .alert { 47 | background: DarkRed; 48 | box-shadow: 0 0 1px rgba(139, 0, 0, 0.25); 49 | color: #fff; 50 | } 51 | 52 | .success { 53 | background: DarkGreen; 54 | box-shadow: 0 0 1px rgba(0, 100, 0, 0.25); 55 | color: #fff; 56 | } 57 | ``` 58 | 59 | ## Purpose and Use Cases 60 | 61 | The Sass, LESS, and stylus languages can be viewed as replacements for plain CSS. Once you have added a CSS preprocessor to your build tooling, there is virtually no reason to write plain CSS, since CSS preprocessors support all features of plain CSS while adding advanced compile-time utilities. 62 | 63 | In practical terms, the primary advantages of CSS preprocessors over plain CSS are: 64 | 65 | 1. Reduced duplication of styles thanks to mixins and inheritance. 66 | 2. Greater control over the scoping of styles thanks to nested selectors. 67 | 3. More powerful variables, color functions, and module systems. 68 | 69 | ## Tradeoffs 70 | 71 | - To use a CSS preprocessor, you generally need to install additional packages and add code to your bundler's configuration file (e.g. `webpack.config.js`). This step is not necessary when using a preconfigured build system like Create React App or Next.js that has built-in support for Sass. 72 | - Since CSS preprocessors are just syntactic sugar over plain CSS, they suffer from some of the same drawbacks: 73 | - React components and CSS rules are written in separate files. This can make it harder to keep track of which styles are for which components as your application grows. 74 | - Styles are not scoped to particular React components, so it is easy to accidentally apply styles more broadly than intended. 75 | - Plain CSS is slowly adding features that were traditionally only available through use of a preprocessor. [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) are supported by all major browsers and nested selectors have been proposed in a [W3C draft](https://www.w3.org/TR/css-nesting-1/). 76 | - Unlike CSS-in-JS libraries, CSS preprocessor code does not integrate with JavaScript. This can make it so you have to define common constants (e.g. colors) in both your stylesheets and JavaScript. 77 | 78 | ## When Should I Consider Using This? 79 | 80 | - You like plain CSS but wish it had more advanced compile-time features. 81 | - You are experiencing code duplication and scoping issues in your plain CSS code. 82 | - You are using [CSS Modules](css-modules.mdx). Sass can be used [in conjunction with CSS Modules](https://create-react-app.dev/docs/adding-a-css-modules-stylesheet) in Create React App. 83 | 84 | ## Further Information 85 | 86 | The best way to learn more about CSS preprocessors is to view their official documentation: 87 | 88 | - [Sass](https://sass-lang.com/) 89 | - [LESS](https://lesscss.org/) 90 | - [stylus](https://stylus-lang.com/) 91 | 92 | ## Example 93 | 94 | This example shows how to create the following component using React and Sass. 95 | 96 | ![A card component with a button](styling-example.png) 97 | 98 | Start by writing your React JSX as usual. Add `className` props to elements you wish to style — we'll use these class names in our Sass. You'll notice that this code is the exact same as what we wrote in the example on the [plain CSS page](plain-css.mdx). 99 | 100 | ```jsx title="Card.jsx" 101 | export function Card() { 102 | return ( 103 |
104 |
105 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 106 |
107 | 108 |
109 | ); 110 | } 111 | ``` 112 | 113 | Now add a Sass file. Use the `.scss` file extension to indicate that we're using the modern SCSS syntax: 114 | 115 | ```scss title="styles.scss" 116 | // Define some variables that we can use throughout our app 117 | $primary: #0d6efd; 118 | $border-color: #ccc; 119 | $box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); 120 | 121 | .card { 122 | border: 1px solid $border-color; 123 | box-shadow: $box-shadow; 124 | border-radius: 0.5rem; 125 | padding: 1rem; 126 | max-width: 200px; 127 | 128 | // This is a nested selector. It only applies to card-content within a card 129 | .card-content { 130 | margin-bottom: 1rem; 131 | } 132 | } 133 | 134 | button { 135 | border: 0; 136 | background-color: $primary; 137 | color: white; 138 | padding: 0.5rem; 139 | font-size: 1rem; 140 | border-radius: 0.25rem; 141 | width: 100%; 142 | 143 | // In a nested selector, an ampersand (&) refers to the parent selector 144 | &:hover { 145 | // Sass provides functions to manipulate colors 146 | background-color: darken($primary, 7%); 147 | } 148 | } 149 | ``` 150 | 151 | Finally, import the Sass file into one of your top-level React files. If you have a file called `App.jsx`, that's a good place for this! 152 | 153 | ```jsx title="App.jsx" 154 | import './styles.scss'; 155 | ``` 156 | -------------------------------------------------------------------------------- /website/docs/styling/emotion.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: emotion 3 | title: 'Emotion' 4 | sidebar_label: 'Emotion' 5 | --- 6 | 7 | ## Description 8 | 9 | TBD 10 | 11 | ## Purpose and Use Cases 12 | 13 | TBD 14 | 15 | ## Tradeoffs 16 | 17 | TBD 18 | 19 | ## When Should I Consider Using This? 20 | 21 | TBD 22 | 23 | ## Further Information 24 | -------------------------------------------------------------------------------- /website/docs/styling/inline-styles.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: inline-styles 3 | title: 'Inline Styles' 4 | sidebar_label: 'Inline Styles' 5 | --- 6 | 7 | ## Description 8 | 9 | Inline styles allow you to attach style rules to individual DOM elements. It is not common to use inline styles as the primary styling method for an application because they result in suboptimal performance and do not support every CSS feature (e.g. pseudoselectors like `:hover`). That said, inline styles are by far the best way to apply _dynamic_ styles like the `transform` property of a draggable element. 10 | 11 | The syntax for inline styles differs between HTML and React. In HTML, you would write the styles as a semicolon-delimited string: 12 | 13 | ```html 14 |
15 | ``` 16 | 17 | while in React, you pass an object to the `style` prop: 18 | 19 | ```jsx 20 | return
; 21 | ``` 22 | 23 | When using the `style` prop, the keys must be in `camelCase` rather than `kebab-case`. This is because React applies your styles to the element using the `HTMLElement.style` property of the DOM. This means that, for the code above, React will do the equivalent of: 24 | 25 | ```jsx 26 | div1.style.backgroundColor = 'purple'; 27 | div1.style.padding = '1rem'; 28 | ``` 29 | 30 | where `div1` is the DOM element created by the JSX. 31 | 32 | ## Purpose and Use Cases 33 | 34 | As stated above, inline styles are not typically used as the main way to style an application. Inline styles are the best option when dealing with dynamic styles, where a style is considered dynamic if either of the following are true: 35 | 36 | 1. The style will change frequently, e.g. the `transform` rule for an element that can be dragged across the screen. 37 | 2. There is a collection of many DOM elements and the style is different for each element. This could arise, for instance, if you are displaying a grid of user profile pictures and using `background-style: url(...)` to show the correct picture in each circle. 38 | 39 | Inline styles can also be a more convenient alternative to traditional CSS when a style depends on a JavaScript variable. For example, you may want to set `visibility` to `hidden` whenever the React component's `currentUser` prop is `null`. Scenarios like this can be often be handled with traditional CSS by conditionally applying a class name, though this is less direct than simply setting `style={{ visibility: currentUser ? 'visible' : 'hidden' }}` in your JSX code. 40 | 41 | ## Tradeoffs 42 | 43 | Inline styles do not support all features of CSS. Unsupported features include: 44 | 45 | - Pseudoselectors like `:hover` and `:focused` 46 | - Pseudoelements like `::before` and `::after` 47 | - Media queries, e.g. `@media (min-width: 600px) { ... }`, which are required for responsive design 48 | - The `@keyframes` rule which is used to define animations 49 | 50 | Inline styles are also generally [less performant](https://simonadcock.com/are-inline-styles-faster-than-atomic-css) than plain CSS, though the difference is not large enough to matter if inline styles are used sparingly. 51 | 52 | Inline styles can result in duplicate code, though this can be addressed by sharing styles via component reuse or importing/exporting shared style objects. 53 | 54 | ## When Should I Consider Using This? 55 | 56 | - The style you want to apply changes frequently, varies from one element to the next, or is controlled by a JavaScript variable. 57 | - The number of elements is small enough that the performance penalty incurred by inline styles will not be noticeable. 58 | - You want a quick way to test out different styles during development. 59 | 60 | ## Further Information 61 | 62 | - [Are inline styles faster than atomic CSS?](https://simonadcock.com/are-inline-styles-faster-than-atomic-css) by Simon Adcock. 63 | - [Inline Styles in HTML](https://www.codecademy.com/article/html-inline-styles) by Codecademy. 64 | 65 | ## Example 66 | 67 | This example shows how to create the following component using React and inline styles. 68 | 69 | ![A card component with a button](styling-example.png) 70 | 71 | All of your code will go in the React JSX — there is no need for an external CSS file. Instead of adding class names to elements, you'll pass your styles directly into the `style` prop. In the code below, we've made it so the button's color changes each time you click it as a fun way to demonstrate the dynamic nature of inline styles. 72 | 73 | ```jsx title="Card.jsx" 74 | export function Card() { 75 | const [hue, setHue] = useState(0); 76 | 77 | return ( 78 |
87 |
88 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 89 |
90 | 104 |
105 | ); 106 | } 107 | ``` 108 | -------------------------------------------------------------------------------- /website/docs/styling/overview.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: overview 3 | title: 'Styling: Overview' 4 | sidebar_label: 'Styling: Overview' 5 | --- 6 | 7 | Appropriate styling can make the difference between a bland, hard-to-use application and beautiful, intuitive application. Broadly speaking, styling a React application is no different from styling any other website. You write styles in CSS and target specific elements on the page using selectors like `h1` or `.navbar`. That said, there are many styling tools that provide additional features over vanilla CSS, such as compile-time variables and deep integration with React. 8 | 9 | This section of the website provides an overview of the most popular styling tools in the React ecosystem and when you should consider using each of them. 10 | 11 | ## Overview of Styling Tools 12 | 13 | - **[Plain CSS](./plain-css.mdx):** Cascading Style Sheets (CSS) is the fundamental styling technology of the web. Plain CSS is the simplest way to style your React app and is the best starting point for those who want to learn frontend web development from the ground up. 14 | - **[CSS preprocessors](./css-preprocessors.mdx):** CSS preprocessors like [Sass](https://sass-lang.com/), [LESS](https://lesscss.org/), and [stylus](https://stylus-lang.com/) enhance CSS with powerful features like variables, mixins, nesting, and inheritance. Your stylesheets must be compiled into normal CSS by the preprocessor before they can be served on the web. 15 | - **[Inline styles](./inline-styles.mdx):** Inline styles allow you to style individual JSX elements in your React code. While inline styles are the best method to apply CSS properties that vary dynamically (like the `transform` property of a draggable element), they are less powerful and performant than other styling solutions. 16 | - **[CSS Modules](./css-modules):** With CSS Modules, you can import a normal CSS file into your JavaScript code and attach class names defined in the CSS to specific React elements. One of the main benefits of CSS Modules is that your styles are scoped to individual React components, preventing issues where styles are unintentionally applied to an unrelated element. Despite the name, CSS Modules are not an official standard. 17 | - **CSS-in-JS libraries:** CSS-in-JS libraries allow you to write real CSS inside your JavaScript code. Most libraries allow you to write styles in CSS (as a string literal) or as a JavaScript object. Like CSS Modules, CSS-in-JS libraries support component-scoped CSS. 18 | - **[styled-components](./styled-components.mdx):** styled-components is a React-specific library that enables you to define wrapper components that attach CSS to ordinary HTML elements and other components. 19 | - **[Emotion](./emotion.mdx):** With Emotion, you can choose between three different approaches to styling. The `css` prop from `@emotion/react` and the `styled` function from `@emotion/styled` are the most ergonomic when working with React. The `css` prop enables you to write real CSS in a method similar to inline styles, while `styled` is largely equivalent to the styled-components library. 20 | 21 | ## Further Information 22 | 23 | - The [MDN Web Docs](https://developer.mozilla.org/) provide extensive documentation on every CSS property. 24 | -------------------------------------------------------------------------------- /website/docs/styling/plain-css.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: plain-css 3 | title: 'Plain CSS' 4 | sidebar_label: 'Plain CSS' 5 | --- 6 | 7 | ## Description 8 | 9 | Cascading Style Sheets (CSS) is _the_ styling technology of the web. All other styling techniques discussed on this site are built on top of CSS, with the exception of inline styles (which are still heavily inspired by CSS. This page covers "plain" CSS, i.e. CSS without any preprocessing steps or JavaScript integration. 10 | 11 | To start using CSS, create a file with the `.css` extension. Then, write a _selector_, which identifies one or more elements on the page, followed by the CSS _properties_ you would like to apply to those elements. For example, the CSS 12 | 13 | ```css 14 | p { 15 | color: red; 16 | margin-bottom: 1.5rem; 17 | } 18 | ``` 19 | 20 | would make every `

` element have red text and a `1.5rem` bottom margin. 21 | 22 | ## Purpose and Use Cases 23 | 24 | CSS is your primary tool for styling and positioning content on the web. 25 | 26 | The are two ways to bring CSS files into your React application. The most common option is to import the CSS file from your JavaScript: 27 | 28 | ```tsx 29 | import './styles/app.css'; 30 | ``` 31 | 32 | though this facility is provided by your bundler (e.g. Webpack) rather than the JavaScript language itself. The other, more traditional method of including CSS files is to add a `` tag to the `` of your HTML document: 33 | 34 | ```html 35 | 36 | 37 | 38 | ``` 39 | 40 | ## Tradeoffs 41 | 42 | While CSS has become more powerful over time, e.g. with the introduction of CSS variables (a.k.a. custom properties), it is still somewhat limited compared the other technologies discussed in this section of the site. Some specific drawbacks of plain CSS are: 43 | 44 | - CSS is a fairly basic language. It does not have built-in support for advanced concepts like inheritance and mixins which can improve maintainability. 45 | - React components and CSS rules are written in separate files. This can make it harder to keep track of which styles are for which components as your application grows. 46 | - Styles are not scoped to particular React components, so it is easy to accidentally apply styles more broadly than intended. 47 | 48 | ## When Should I Consider Using This? 49 | 50 | Plain CSS is an appropriate styling tool for virtually any website, though it's especially useful when: 51 | 52 | - You are new to web development and want start with the basics. 53 | - You are working on a relatively small application where the drawbacks of CSS are less likely to be an issue. 54 | - You dislike complex build processes and want to start writing application code immediately. 55 | - Performance is critical. Plain CSS avoids the CPU overhead incurred by CSS-in-JS libraries. 56 | 57 | ## Further Information 58 | 59 | - The [MDN Web Docs](https://developer.mozilla.org/) provide extensive documentation on every CSS property. 60 | - [BEM](http://getbem.com/introduction/) is a CSS methodology that helps keep things organized as a codebase grows. 61 | 62 | ## Example 63 | 64 | This example shows how to create the following component using React and CSS. 65 | 66 | ![A card component with a button](styling-example.png) 67 | 68 | Start by writing your React JSX as usual. Add `className` props to elements you wish to style — we'll use these class names in our CSS. 69 | 70 | ```jsx title="Card.jsx" 71 | export function Card() { 72 | return ( 73 |

74 |
75 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 76 |
77 | 78 |
79 | ); 80 | } 81 | ``` 82 | 83 | Now add a CSS file: 84 | 85 | ```css title="styles.css" 86 | /* .card is a selector which targets all elements with className="card" */ 87 | .card { 88 | border: 1px solid #ccc; 89 | border-radius: 0.5rem; 90 | padding: 1rem; 91 | max-width: 200px; 92 | 93 | /* There are multiple formats for defining colors in CSS. This rule uses 94 | * rgba to make a black shadow that is nearly transparent. */ 95 | box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); 96 | } 97 | 98 | /* Target all `card-content` elements that are within a `card` */ 99 | .card .card-content { 100 | margin-bottom: 1rem; 101 | } 102 | 103 | /* Target all buttons, regardless of class name */ 104 | button { 105 | border: 0; 106 | background-color: #0d6efd; 107 | color: white; 108 | padding: 0.5rem; 109 | font-size: 1rem; 110 | border-radius: 0.25rem; 111 | width: 100%; 112 | } 113 | 114 | /* Make the button darker when the user hovers over it */ 115 | button:hover { 116 | background-color: #025ce3; 117 | } 118 | ``` 119 | 120 | Finally, import the CSS file into one of your top-level React files. If you have a file called `App.jsx`, that's a good place for this! 121 | 122 | ```jsx title="App.jsx" 123 | import './styles.css'; 124 | ``` 125 | -------------------------------------------------------------------------------- /website/docs/styling/styled-components.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: styled-components 3 | title: 'Styled Components' 4 | sidebar_label: 'Styled Components' 5 | --- 6 | 7 | ## Description 8 | 9 | TBD 10 | 11 | ## Purpose and Use Cases 12 | 13 | TBD 14 | 15 | ## Tradeoffs 16 | 17 | TBD 18 | 19 | ## When Should I Consider Using This? 20 | 21 | TBD 22 | 23 | ## Further Information 24 | -------------------------------------------------------------------------------- /website/docs/styling/styling-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markerikson/react-community-tools-practices-cheatsheet/2e081f6d0d51f1586690ab0fb51c9f7ab2353c05/website/docs/styling/styling-example.png -------------------------------------------------------------------------------- /website/docs/use-cases/choosing-library-for-existing-project.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: choosing-library-for-existing-project 3 | title: Choosing a Library 4 | sidebar_label: Choosing a Library for an Existing Project 5 | slug: choosing-library-for-existing-project 6 | --- 7 | -------------------------------------------------------------------------------- /website/docs/use-cases/starting-a-new-project.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: starting-a-new-project 3 | title: Starting a New Project 4 | sidebar_label: Starting a New Project 5 | slug: starting-a-new-project 6 | --- 7 | -------------------------------------------------------------------------------- /website/docs/use-cases/starting-with-react.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: starting-with-react 3 | title: Starting with React 4 | sidebar_label: Starting with React 5 | slug: starting-with-react 6 | --- 7 | -------------------------------------------------------------------------------- /website/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: 'React Common Tools and Practices', 3 | tagline: 'Common Tools and Practices in the React Community', 4 | url: 'https://react-community-tools-practices-cheatsheet.netlify.app', 5 | baseUrl: '/', 6 | favicon: 'img/favicon.ico', 7 | projectName: 'react-community-tools-practices-cheatsheet', 8 | themeConfig: { 9 | navbar: { 10 | title: 'Common Tools & Practices', 11 | logo: { 12 | alt: 'My Site Logo', 13 | src: 'img/logo.svg', 14 | }, 15 | items: [ 16 | { 17 | to: '/common-mistakes', 18 | label: 'Common Mistakes', 19 | position: 'right', 20 | }, 21 | { 22 | to: '/glossary', 23 | label: 'Glossary', 24 | position: 'right', 25 | }, 26 | { 27 | to: '/use-cases/choosing-library-for-existing-project', 28 | label: 'Use Cases', 29 | position: 'right', 30 | }, 31 | { 32 | to: '/state-management/overview', 33 | label: 'State Management', 34 | position: 'right', 35 | }, 36 | ], 37 | }, 38 | footer: { 39 | style: 'dark', 40 | links: [ 41 | { 42 | title: 'Docs', 43 | items: [ 44 | { 45 | label: 'Common Mistakes', 46 | to: '/common-mistakes', 47 | }, 48 | { 49 | label: 'Glossary', 50 | to: '/glossary', 51 | }, 52 | { 53 | label: 'Use Cases', 54 | to: '/use-cases/choosing-library-for-existing-project', 55 | }, 56 | { 57 | label: 'State Management', 58 | to: '/state-management/overview', 59 | }, 60 | { 61 | label: 'How To', 62 | to: '/how-to', 63 | }, 64 | ], 65 | }, 66 | { 67 | title: 'Community', 68 | items: [ 69 | { 70 | label: 'Github Discussion', 71 | href: 'https://github.com/markerikson/react-community-tools-practices-cheatsheet/discussions/1', 72 | }, 73 | ], 74 | }, 75 | { 76 | title: 'More', 77 | items: [ 78 | { 79 | label: 'GitHub', 80 | href: 'https://github.com/markerikson/react-community-tools-practices-cheatsheet', 81 | }, 82 | ], 83 | }, 84 | ], 85 | copyright: `Copyright © ${new Date().getFullYear()} React Community. Built with Docusaurus.`, 86 | }, 87 | }, 88 | presets: [ 89 | [ 90 | '@docusaurus/preset-classic', 91 | { 92 | docs: { 93 | path: './docs', 94 | routeBasePath: '/', 95 | include: ['**/*.{md,mdx}'], 96 | sidebarPath: require.resolve('./sidebars.js'), 97 | }, 98 | theme: { 99 | customCss: require.resolve('./src/css/custom.css'), 100 | }, 101 | }, 102 | ], 103 | ], 104 | }; 105 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "docusaurus": "docusaurus", 4 | "start": "docusaurus start", 5 | "build": "docusaurus build", 6 | "swizzle": "docusaurus swizzle", 7 | "deploy": "docusaurus deploy", 8 | "serve": "docusaurus serve", 9 | "clear": "docusaurus clear", 10 | "prettier": "prettier ." 11 | }, 12 | "dependencies": { 13 | "@docusaurus/core": "2.0.0-beta.20", 14 | "@docusaurus/preset-classic": "2.0.0-beta.20", 15 | "@mdx-js/react": "^1.6.22", 16 | "clsx": "^1.1.1", 17 | "prettier": "^2.6.2", 18 | "react": "^17.0.2", 19 | "react-dom": "^17.0.2" 20 | }, 21 | "browserslist": { 22 | "production": [ 23 | ">0.5%", 24 | "not dead", 25 | "not op_mini all" 26 | ], 27 | "development": [ 28 | "last 1 chrome version", 29 | "last 1 firefox version", 30 | "last 1 safari version" 31 | ] 32 | }, 33 | "packageManager": "yarn@3.2.0" 34 | } 35 | -------------------------------------------------------------------------------- /website/sidebars.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | docs: { 3 | 'Common Mistakes': ['common-mistakes/common-mistakes'], 4 | Glossary: ['glossary/glossary'], 5 | 'How To': ['how-to/how-to'], 6 | 'State Management': [ 7 | 'state-management/overview', 8 | 'state-management/react-state', 9 | 'state-management/redux', 10 | 'state-management/mobx', 11 | 'state-management/xstate', 12 | 'state-management/poimandres', 13 | ], 14 | 'Data Fetching and Caching': ['data-fetching-caching/overview'], 15 | Styling: [ 16 | 'styling/overview', 17 | 'styling/plain-css', 18 | 'styling/css-preprocessors', 19 | 'styling/inline-styles', 20 | 'styling/css-modules', 21 | 'styling/styled-components', 22 | 'styling/emotion', 23 | ], 24 | 'Use Cases': [ 25 | 'use-cases/choosing-library-for-existing-project', 26 | 'use-cases/starting-a-new-project', 27 | 'use-cases/starting-with-react', 28 | ], 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /website/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable docusaurus/copyright-header */ 2 | /** 3 | * Any CSS included here will be global. The classic template 4 | * bundles Infima by default. Infima is a CSS framework designed to 5 | * work well for content-centric websites. 6 | */ 7 | 8 | /* You can override the default Infima variables here. */ 9 | :root { 10 | --ifm-color-primary: #25c2a0; 11 | --ifm-color-primary-dark: rgb(33, 175, 144); 12 | --ifm-color-primary-darker: rgb(31, 165, 136); 13 | --ifm-color-primary-darkest: rgb(26, 136, 112); 14 | --ifm-color-primary-light: rgb(70, 203, 174); 15 | --ifm-color-primary-lighter: rgb(102, 212, 189); 16 | --ifm-color-primary-lightest: rgb(146, 224, 208); 17 | --ifm-code-font-size: 95%; 18 | } 19 | 20 | .docusaurus-highlight-code-line { 21 | background-color: rgb(72, 77, 91); 22 | display: block; 23 | margin: 0 calc(-1 * var(--ifm-pre-padding)); 24 | padding: 0 var(--ifm-pre-padding); 25 | } 26 | -------------------------------------------------------------------------------- /website/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import clsx from 'clsx'; 3 | import Layout from '@theme/Layout'; 4 | import Link from '@docusaurus/Link'; 5 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 6 | import useBaseUrl from '@docusaurus/useBaseUrl'; 7 | import styles from './styles.module.css'; 8 | 9 | const features = [ 10 | { 11 | title: 'Slightly Opinionated', 12 | imageUrl: 'img/undraw_docusaurus_mountain.svg', 13 | description: ( 14 | <> 15 | The goal of this site is to provide slightly opinionated guidance on 16 | libraries in the React ecosystem. 17 | 18 | ), 19 | }, 20 | { 21 | title: 'Filling a Gap', 22 | imageUrl: 'img/undraw_docusaurus_tree.svg', 23 | description: ( 24 | <> 25 | It can be difficult to know what tool to use for which occasion. React 26 | Common Tools and Practices is here to keep you informed and help you 27 | better weigh your options. 28 | 29 | ), 30 | }, 31 | { 32 | title: 'Community Driven', 33 | imageUrl: 'img/undraw_docusaurus_react.svg', 34 | description: <>Built by the community for the community., 35 | }, 36 | ]; 37 | 38 | function Feature({ imageUrl, title, description }) { 39 | const imgUrl = useBaseUrl(imageUrl); 40 | return ( 41 |
42 | {imgUrl && ( 43 |
44 | {title} 45 |
46 | )} 47 |

{title}

48 |

{description}

49 |
50 | ); 51 | } 52 | 53 | function Home() { 54 | const context = useDocusaurusContext(); 55 | const { siteConfig = {} } = context; 56 | return ( 57 | 61 |
62 |
63 |

{siteConfig.title}

64 |

{siteConfig.tagline}

65 |
66 | 73 | Get Started 74 | 75 |
76 |
77 |
78 |
79 | {features && features.length > 0 && ( 80 |
81 |
82 |
83 | {features.map((props, idx) => ( 84 | 85 | ))} 86 |
87 |
88 |
89 | )} 90 |
91 |
92 | ); 93 | } 94 | 95 | export default Home; 96 | -------------------------------------------------------------------------------- /website/src/pages/styles.module.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable docusaurus/copyright-header */ 2 | 3 | /** 4 | * CSS files with the .module.css suffix will be treated as CSS modules 5 | * and scoped locally. 6 | */ 7 | 8 | .heroBanner { 9 | padding: 4rem 0; 10 | text-align: center; 11 | position: relative; 12 | overflow: hidden; 13 | } 14 | 15 | @media screen and (max-width: 966px) { 16 | .heroBanner { 17 | padding: 2rem; 18 | } 19 | } 20 | 21 | .buttons { 22 | display: flex; 23 | align-items: center; 24 | justify-content: center; 25 | } 26 | 27 | .features { 28 | display: flex; 29 | align-items: center; 30 | padding: 2rem 0; 31 | width: 100%; 32 | } 33 | 34 | .featureImage { 35 | height: 200px; 36 | width: 200px; 37 | } 38 | -------------------------------------------------------------------------------- /website/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markerikson/react-community-tools-practices-cheatsheet/2e081f6d0d51f1586690ab0fb51c9f7ab2353c05/website/static/.nojekyll -------------------------------------------------------------------------------- /website/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markerikson/react-community-tools-practices-cheatsheet/2e081f6d0d51f1586690ab0fb51c9f7ab2353c05/website/static/img/favicon.ico -------------------------------------------------------------------------------- /website/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /website/static/img/undraw_docusaurus_mountain.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /website/static/img/undraw_docusaurus_react.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /website/static/img/undraw_docusaurus_tree.svg: -------------------------------------------------------------------------------- 1 | docu_tree --------------------------------------------------------------------------------