Giter Club home page Giter Club logo

advanced-react-patterns's Introduction

Learn how to build simple and flexible React Components and Hooks using modern patterns

Not only learn great patterns you can use but also the strengths and weaknesses of each, so you know which to reach for to provide your custom hooks and components the flexibility and power you need.



Build Status GPL 3.0 License Code of Conduct

Prerequisites

  • The more experience you have with building React abstractions, the more helpful this workshop will be for you.

Pre-workshop Resources

Here are some resources you can read before taking the workshop to get you up to speed on some of the tools and concepts we'll be covering:

System Requirements

  • git v2.18 or greater
  • NodeJS v18 or greater
  • npm v8 or greater

All of these must be available in your PATH. To verify things are set up properly, you can run this:

git --version
node --version
npm --version

If you have trouble with any of these, learn more about the PATH environment variable and how to fix it here for windows or mac/linux.

Setup

This is a pretty large project (it's actually many apps in one) so it can take several minutes to get everything set up the first time. Please have a strong network connection before running the setup and grab a snack.

Follow these steps to get this set up:

git clone --depth 1 https://github.com/epicweb-dev/advanced-react-patterns.git
cd advanced-react-patterns
npm run setup

If you experience errors here, please open an issue with as many details as you can offer.

The Workshop App

Learn all about the workshop app on the Epic Web Getting Started Guide.

Kent with the workshop app in the background

advanced-react-patterns's People

Contributors

0xnoob avatar abeplays avatar alexmunoz avatar allcontributors[bot] avatar aprillion avatar bobbywarner avatar compuives avatar creador-dev avatar daleseo avatar deniztetik avatar deriegle avatar devneill avatar emipc avatar emzoumpo avatar fullchee avatar jacobparis avatar jasonruesch avatar jdorfman avatar jorgeruvalcaba avatar jpotts18 avatar kentcdodds avatar kkstrk avatar marcosvega91 avatar marioleed avatar michaeldeboey avatar nawok avatar patrickclery avatar pritamsangani avatar pvinis avatar ruffeng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

advanced-react-patterns's Issues

Official Site?

Is this the official site for this repo or is it an infringement? I'm signed up for Epic React and the content looks extremely similar but the name seems to come from here.

I'm looking for a good place to link the Prop Getter pattern and I don't want to peddle in imposters.

Workshop Setup: no `config/tsconfig.exercise.json` file

There's no config/tsconfig.exercise.json file, even though the Readme is suggesting editing it.

I'm preparing for today's workshop, and the readme here in the "TypeScript" part suggests that, to enable the TS Strict mode, one should configure it in config/tsconfig.exercise.json file. However, there is no such file, nor config/ directory. I am not certain if it's worth the effort, but I think either rewording this ("create config/tsconfig...") or creating a placeholder tsconfig file there should help with first-time setup of the repo.

Question: throwing an error inside the reduce function

Hey,

I was wondering are there any significant advantages to throwing an error inside the reducer function?
IMHO, it is a side effect and the reducer function should not have that.

I do see what you were trying to do there but I believe it is a bad user experience even though the developer was not careful and dispatched an event that's not handled by the reducer.

Thanks.

Exercise 2, Advanced React Patterns - Unclear explanation

In exercise 2, workshop Advanced React Patterns, I understand how to implement the pattern but don't quite get the problem it solves.

Quoting:

We have a Toggle component that manages the state, and we want to render different parts of the UI however we want. We want control over the presentation of the UI.

🦉 The fundamental challenge you face with an API like this is the state shared between the components is implicit, meaning that the developer using your component cannot actually see or interact with the state (on) or the mechanisms for updating that state (toggle) that are being shared between the components.

So in this exercise, we’ll solve that problem by providing the compound components with the props they need implicitly using React.cloneElement.

So what is an API like this ? Because the example is not complete / working yet.
And basically the passing state from parent to children is still implicit after the pattern is applied. So what is the problem it solves here? Thanks!

process is not defined error. Interactivity blocked

Hello!

I started running into this process is not defined error yesterday. I did not run into this same error in any of the previous modules. It's happening after every hot-reload.

image

After a bit of googling, I found this create-react-app issue: facebook/create-react-app#11773. Looks like the same issue?

Here's my setup:

image

Steps to Repro:

  1. Clone repo
  2. Run setup and start project as per readme.
  3. Trigger a hot reload by making any change to code & save.

Error will appear in console. It's happening on every page, including the isolated pages.

Once the error is triggered, I am unable to interact with the page. Buttons don't work and scrolling is disabled. This might be due to an iframe that blocks everything. This was also mentioned in the issue referenced above.

Here's the iframe I am seeing appear after the error is triggered:
image

Let me know if you need anything else from my end.

Thanks!

Invalid value for prop `toggle` on <span>

I'm following along with your course and exercise 2 gives me this error when I implement your solution:

Warning: Invalid value for prop `toggle` on <span> tag. Either remove it from the element, or pass a string or number value to keep it in the DOM.

The toggle does not function correctly

Bug: unable to reproduce the `useLayoutEffect: auto-scrolling textarea` chapter

Chapter

useLayoutEffect: auto-scrolling textarea -> useLayoutEffect Solution

Description

The author describes a situation in the video: Since useEffect is always executed after layout and paint, the UI may become torn.
The author then demonstrates this situation using the original code of 04.js, specifically:

  1. Click the add message button.
  2. The message box adds a message immediately.
  3. After a few moments, the information box is positioned to the position of the new information.

The problem I'm having is that I can't reproduce the example.

I found the reason from the React 18 Working Group: In React 18, useEffect fires synchronously when it's the result of a discrete input.

You can find a more detailed description here.

I would like to give the author feedback on this matter, which is the purpose of this issue.

Element type is invalid error upon starting the app

I'm seeing the following error after running npm start: Element type is invalid. Received a promise that resolves to: /static/media/01.5905cfaa607076924a2c.md. Lazy element type must resolve to a class or function.
Validation is passing as well.

Heres the stack trace im seeing in the console:

react-dom.production.min.js:186 Error: Minified React error #306; visit https://reactjs.org/docs/error-decoder.html?invariant=306&args[]=%2Fstatic%2Fmedia%2F01.5905cfaa607076924a2c.md&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
    at ws (main.e273faf5.js:2:260313)
    at gu (main.e273faf5.js:2:248394)
    at vu (main.e273faf5.js:2:248322)
    at mu (main.e273faf5.js:2:248185)
    at au (main.e273faf5.js:2:244969)
    at ru (main.e273faf5.js:2:243520)
    at k (main.e273faf5.js:2:291290)
    at MessagePort.P (main.e273faf5.js:2:291824)

Both rerendering and reloading do not fix the issue

Screen Shot 2022-05-20 at 10 44 34 AM

Opinion on compound components with default children

In excerise 03 the Toggle component takes children

function Toggle({children}) {
  const [on, setOn] = React.useState(false)
  const toggle = () => setOn(!on)

  return (
    <ToggleContext.Provider value={{on, toggle}}>
      {children}
    </ToggleContext.Provider>
  )
}

but what if it took default children

function Toggle({ children }) {
  const [on, setOn] = React.useState(false);
  const toggle = () => setOn(!on);

  return (
    <ToggleContext.Provider value={{ on, toggle }}>
      {children || (
        <>
          <ToggleOn>The button is on</ToggleOn>
          <ToggleOff>The button is off</ToggleOff>
          <ToggleButton />
        </>
      )}
    </ToggleContext.Provider>
  );
}

and now you can use it like this

    <div>
      {/* default children */}
      <Toggle />

      {/* OR */}

      {/* explicit children */}
      <Toggle>
        <ToggleOn>This button is on</ToggleOn>
        <ToggleOff>This button is off</ToggleOff>
        <ToggleButton />
      </Toggle>
    </div>

what are your opinion on giving default children? could this lead to any problems?

node setup fails with node 17

Although the Readme states that node 17 should be working, the node setup command fails for me with the following message:

▶️  Starting workshop setup...
      Running the following command: npx "https://gist.github.com/kentcdodds/bb452ffe53a5caa3600197e1d8005733" -q
    ▶️  Starting: System Validation
          Ensuring the correct versions of tools are installed on this computer.
          Running the following command: npx "https://gist.github.com/kentcdodds/abbc32701f78fa70298d444c2303b6d9"
There were errors validating the compatibility of this computer:

    This computer has [email protected] installed, but node@12 || 14 || 15 || 16 is required. Please update node: https://nodejs.org


If you would like to just ignore this error, then feel free to do so and install dependencies as you normally would in "/Users/roda/Documents/Development/advanced-react-patterns". Just know that things may not work properly if you do...
    🚨  Failure: System Validation. Please review the messages above for information on how to troubleshoot and resolve this issue.

Design pattern for switching product list layout

Kent I'm taking ur React course and I'm here in this specific section about patterns, I want to apply the knowledge adquired refactorimg this product list which should render diferent layouts:

  • stacked vertically (default)
  • horizontal (scroll)
  • grid

The idea is to use the same component(s) to support all formats(DRY), here the layouts that I want to implement.

What I have

ProductList

Responsible for rendering a list of products. This component decide how to be rederized the list, in vertical (default), horizontal (scroll), or grid mode.

// ProductList.js

import React from 'react'
import {Dimensions, FlatList, View} from 'react-native'

// I'm using typescript, for the purpose of simplicity I don't put all the types
// in the code. Only the ones that define what each property of the component does.
export type ProductListProps = {
  /**
   * Products to display in the list
   */
  products: Product[]
  /**
   * If true, renders items next to each other horizontally instead of stacked
   * vertically.
   */
  showHorizontalList?: boolean
  /**
   * Tell how many columns in Grid.
   */
  numColumns?: number
  /**
   * If true, renders product list item content as column
   */
  productContentAsColumn?: boolean
}

function ProductList({
  products,
  numColumns = 1, 
  showHorizontalList = false,
}) {
  const getLayoutManager = () => {
    const layoutManager = {}
    if (showHorizontalList) {
      layoutManager.horizontal = true
      layoutManager.showsHorizontalScrollIndicator = false
      layoutManager.ItemSeparatorComponent = ProductListItemSeparator
      layoutManager.contentContainerStyle = {padding: 16}
    } else {
      layoutManager.numColumns = numColumns
    }

    return layoutManager
  }

  const renderItemRow = ({item}) => (
    <ProductListItem
      product={item}
      viewContainerStyle={{
        width: Dimensions.get('window').width / numColumns,
      }}
      // change item content direaction from `row` to 'column'
      columnContainerStyle={{flexDirection: 'column'}}
    />
  )

  return (
    <FlatList
      {...getLayoutManager()}
      // Pass a changing value to the `key` prop to update the columns number on the fly
      key={numColumns}
      data={products}
      renderItem={renderItemRow}
    />
  )
}

ProductListItem

Responsible for rendering list's item content. From here, you can modify the itemContainerStyle to decide how much space each item should occupy or contentContainerStyle to decide whether it should be rendered as a row(default) or column(card).

// ProductListItem.js

import {View} from 'react-native'

export type ProductListItemProps = {
  /**
   * Product to display
   */
  product: FeaturedProduct
  /**
   * With this styles you can definde the space can be filled by each item in the list
   */
  itemContainerStyle?: StyleProp<ViewStyle>
  /**
   * With this styles you can define if item content should render as `row` or `column`
   */
  itemContentStyle?: StyleProp<ViewStyle>
}

function ProductListItem({
  product,
  itemContainerStyle = {},
  itemContentStyle = {},
}) {
  return (
    <View style={itemContainerStyle}>
      <View style={[styles.row, itemContentStyle]}>
        // any content can be placed here
      </View>
    </View>
  )
}

const styles = StyleSheet.create({
  row: {
    flexDirection: 'row',
  },
})

Problem

This nested component design can be really messy(creating ProducListItem inside ProducList). I would like to know if a specific react design pattern can be applied in this case to decouple list(parent) to items(childs), taking into account that the children must access the parent's state/props in order to know what kind of layout should be rendered. I'm think that Compound Components can fit here but I'm not sure, any advice in what design pattern can I use here.

Changelog

Here's what's going to be different in the next version of the advanced-react-patterns workshop (you can find all these changes in the next branch until the videos are re-recorded):

  • Everything is TypeScript. There's a new script you can run to remove the TypeScript automatically if you want: ./scripts/remove-ts.
  • General improvements to the workshop content based on feedback from learners
  • Completely removed exercise 1 (Context Module Functions). It's an extremely niche pattern that even I haven't actually found useful in any of my projects.
  • Completely removed exercise 2 (Compound Components w/ React.cloneElement). There's really no great reason to not just use context which we teach in exercise 3.
  • Add a new exercise 1 titled: "Latest Ref". This is a simple pattern that I find myself using regularly.
  • Add a new exercise 2 titled: "Composition and Layout Components". This is another simple pattern I find myself using regularly.
  • Add a new exercise 5 titled: "State Initializer". This is a pattern I used to have in the workshop then removed and now it's back again because I had enough people who were surprised when they saw it hiding there in the other exercises. It allows users to reset your component/hook's state to the initial value.
  • In exercise 6 (state reducer) I removed extra credit 2 about action types since we're using typescript now and action types are no longer needed. On a related note we also no longer don't need the default case for our reducer switch statement because we're using typescript.
  • In exercise 7 (control props) I drastically simplified the extra credits by making a single useControlPropWarnings hook and providing that for folks to just import. Now it's just one extra credit. It really should just be an open source library people can use. It's not very complicated, but it's hard to come up with on your own and doesn't really add much to your learning. A lot of people had trouble with this one and I think this change will improve it quite a bit.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.