Giter Site home page Giter Site logo

kentcdodds / advanced-react-patterns-v2 Goto Github PK

View Code? Open in Web Editor NEW
1.5K 45.0 567.0 297 KB

Created with CodeSandbox

Home Page: https://codesandbox.io/s/github/kentcdodds/advanced-react-patterns-v2

HTML 2.33% JavaScript 96.35% CSS 1.31%
kcd-edu react javascript

advanced-react-patterns-v2's Introduction

Advanced React Patterns v2

๐Ÿ‘‹ hi there! My name is Kent C. Dodds! This is a workshop repo to teach you about using React Component Patterns to make your react components more useful and reusable without sacrificing simplicity.

Following along with Frontend Masters?

Head to the frontend-masters branch to get started!

chat-badge Build Status AppVeyor Build Status Code Coverage MIT License All Contributors

PRs Welcome Code of Conduct Watch on GitHub Star on GitHub Tweet

System Requirements

  • git v2.14.1 or greater
  • NodeJS v8.9.4 or greater
  • npm v5.6.0 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

You may be able to work through the entire workshop in the browser. Go to this codesandbox and you should be good to go.

If you'd rather be able to work through the workshop on your own computer, then follow the following instructions.

After you've made sure to have the correct things (and versions) installed, you should be able to just run a few commands to get set up:

git clone https://github.com/kentcdodds/advanced-react-patterns-v2.git
cd advanced-react-patterns-v2
npm run setup --silent

This may take a few minutes. It will ask you for your email. This is optional and just automatically adds your email to the links in the project to make filling out some forms easier If you get any errors, please read through them and see if you can find out what the problem is. You may also want to look at Troubleshooting. If you can't work it out on your own then please file an issue and provide all the output from the commands you ran (even if it's a lot).

Running the app

To get the app up and running (and really see if it worked), run:

npm start

This should start up your browser. If you're familiar, this is a standard react-scripts application.

You can also open the deployment of the app on Netlify.

Running the tests

npm test

This will start Jest in watch mode. Read the output and play around with it.

Your goal will be to go into each test, swap the final version for the exercise version in the import, and make the tests pass

Helpful Emoji ๐Ÿจ ๐Ÿ’ฐ ๐Ÿ’ฏ

Each exercise has comments in it to help you get through the exercise. Kody the Koala Bear and Marty the Money Bag are here to help you. Kody ๐Ÿจ will tell you when there's something specific you should do, and Marty ๐Ÿ’ฐ will give you specific tips along the way. Should you finish early, Hannah the Hundred Points Symbol ๐Ÿ’ฏ will give you some additional challenges that you can try!

Troubleshooting

"npm run setup" command not working

Here's what the setup script does. If it fails, try doing each of these things individually yourself:

# verify your environment will work with the project
node ./scripts/verify

# install dependencies
npm install

# verify the project is ready to run
npm run build
npm run test:coverage

If any of those scripts fail, please try to work out what went wrong by the error message you get. If you still can't work it out, feel free to open an issue with all the output from that script. I will try to help if I can.

Contributors

Thanks goes to these wonderful people (emoji key):

Kent C. Dodds
Kent C. Dodds

๐Ÿ’ป ๐Ÿ“– ๐Ÿš‡ โš ๏ธ
FWeinb
FWeinb

๐Ÿ› ๐Ÿค”
David Lannoye
David Lannoye

๐Ÿ› ๐Ÿ“–
Colin Cummings
Colin Cummings

๐Ÿ’ป โš ๏ธ
Benji Koltai
Benji Koltai

๐Ÿ“–
Sumit Bagga
Sumit Bagga

๐Ÿ“–
Yury Tarabanko
Yury Tarabanko

๐Ÿ’ป
Alex Wendte
Alex Wendte

๐Ÿ’ป
rahildar
rahildar

๐Ÿ’ป
Joshua
Joshua

๐Ÿ’ป
Nicolas Orchow
Nicolas Orchow

โš ๏ธ
Eric Berry
Eric Berry

๐Ÿ”

This project follows the all-contributors specification. Contributions of any kind welcome!

License

This material is available for private, non-commercial use under the GPL version 3. If you would like to use this material to conduct your own workshop, please contact me at [email protected]

advanced-react-patterns-v2's People

Contributors

alexwendte avatar allcontributors[bot] avatar andrewmcodes avatar antonhalim avatar awolf81 avatar baggasumit avatar bkoltai avatar colinrcummings avatar dlannoye avatar giuseppeg avatar gpetrioli avatar gregjarvez avatar j-u-p-iter avatar konekoya avatar kuldeepkeshwar avatar mgostisha avatar mknepprath avatar norchow avatar ofhouse avatar rafaesc avatar samiskin avatar tarabyte 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  avatar  avatar  avatar  avatar

advanced-react-patterns-v2's Issues

First exercise - 01: Switch button never change its state!

Hello,

I was going through the codesandbox link - https://codesandbox.io/s/github/kentcdodds/advanced-react-patterns-v2 to quickly go through the exercises. I'm in the first exercise and for some reason, the toggle button didn't change its state though I applied the setState appropriately. BTW, the final exercise also exhibited the same behavior. Am I missing anything?

Oh, yes the toggle() looks same as it's there in the final exercise of 01.

Thanks,
KSM

Why doesn't changing the parent state update both Toggle's?

Hi, thank you for your react patterns video. I hope it's okay to ask questions here.

In your control props videos, I was confused as to why the following didn't work. I modified the Toggle component so that it sets the initial state as the prop that was sent in. I assumed that re-rendering the parent will re-render the children as well. In this case, shouldn't both Toggle components be re-rendered with a fresh set of props?

class Toggle extends React.Component {
  // state = {on: false}
  state = this.props.on
  ...
class Usage extends React.Component {
  state = {bothOn: false}
  
  handleToggle = on => {
    this.setState({bothOn: on})
  }
  render() {
    const {bothOn} = this.state
    const {toggle1Ref, toggle2Ref} = this.props
    return (
      <div>
        <Toggle
          on={bothOn}
          onToggle={this.handleToggle}
          ref={toggle1Ref}
        />
        <Toggle
          on={bothOn}
          onToggle={this.handleToggle}
          ref={toggle2Ref}
        />
      </div>
    )
  }
}

Add extra credit for exercise 02

Just a reminder for you to add the extra credit for the scenario in which the consumer of the compound component is required to be able to add their own HTML tags as children.

i.e. being able to do this in the usage section:

  <Toggle onToggle={onToggle}>
      <Toggle.On>The button is on</Toggle.On>
      <Toggle.Off>The button is off</Toggle.Off>
      <Toggle.Button />
      <span>Something</span>
    </Toggle>

๐Ÿ˜ƒ

npm start doesn't works

On windows, this project ran fine.

However, on my Mac. Following the same steps gives me an error


sh: react-scripts: command not found
npm ERR! file sh
npm ERR! code ELIFECYCLE
npm ERR! errno ENOENT
npm ERR! syscall spawn
npm ERR! [email protected] start: `react-scripts start`
npm ERR! spawn ENOENT
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/vedant/.npm/_logs/2018-11-25T05_46_33_446Z-debug.log

I tried

1. rm -rf node-modules && npm install && npm start
2. npm i -D react-scripts && npm start

And it still fails

There might be a problem with the project dependency tree. It is likely not a bug in Create React App, but something you need to fix locally.

The react-scripts package provided by Create React App requires a dependency:

"babel-loader": "8.1.0"

Don't try to install it manually: your package manager does it automatically.
However, a different version of babel-loader was detected higher up in the tree:

C:\Users\Rk\node_modules\babel-loader (version: 8.0.6)

Manually installing incompatible versions is known to cause hard-to-debug issues.

If you would prefer to ignore this check, add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
That will permanently disable this message but you might encounter other issues.

To fix the dependency tree, try following the steps below in the exact order:

  1. Delete package-lock.json (not package.json!) and/or yarn.lock in your project folder.
  2. Delete node_modules in your project folder.
  3. Remove "babel-loader" from dependencies and/or devDependencies in the package.json file in your project folder.
  4. Run npm install or yarn, depending on the package manager you use.

In most cases, this should be enough to fix the problem.
If this has not helped, there are a few other things you can try:

  1. If you used npm, install yarn (http://yarnpkg.com/) and repeat the above steps with it instead.
    This may help because npm has known issues with package hoisting which may get resolved in future versions.

  2. Check if C:\Users\Rk\node_modules\babel-loader is outside your project directory.
    For example, you might have accidentally installed something in your home folder.

  3. Try running npm ls babel-loader in your project folder.
    This will tell you which other package (apart from the expected react-scripts) installed babel-loader.

If nothing else helps, add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
That would permanently disable this preflight check in case you want to proceed anyway.

P.S. We know this message is long but please read the steps above :-) We hope you find them helpful!

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start: react-scripts start
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Rk\AppData\Roaming\npm-cache_logs\2020-08-24T05_54_18_857Z-debug.log

"npm i" shows 40 vulnerabilities

Thanks Kent & other contributors for all your efforts. Just wanted to point out security vulnerabilities npm reports as it completes (please note there isn't any issue with the installation):

image

Here is the summary of npm audit - https://file-eqqipuzafp.now.sh/

Environment Details:
OS: macOS Sierra - 10.12.6
Node: v8.9.1
NPM: v6.0.1

Getting error for Prop getters

Here the stacktrace

TypeError: getTogglerProps is not a function. (In 'getTogglerProps({
    on
  })', 'getTogglerProps' is undefined)
(anonymous function)
src/exercises/06.js:50
  47 | return (
  48 |   <Toggle onToggle={onToggle}>
  49 |     {({on, getTogglerProps}) => (
> 50 |       <div>
^ 51 |         <Switch {...getTogglerProps({on})} />
  52 |         <hr />
  53 |         <button

npm run build error

I also ran the npm run setup command separately and it get the same error on npm run build.

I followed the instructions on the error message, but no dice.

In step 3, it says remove webpack, but there is no webpack on package.json.
I reran the command with yarn, but got the same error.

The error message also says to add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
Couldn't find any .env file.

Thanks for the help

There might be a problem with the project dependency tree.
It is likely not a bug in Create React App, but something you need to fix locally.

The react-scripts package provided by Create React App requires a dependency:

  "webpack": "3.10.0"

Don't try to install it manually: your package manager does it automatically.
However, a different version of webpack was detected higher up in the tree:

  /Users/home/node_modules/webpack (version: 4.6.0) 

Manually installing incompatible versions is known to cause hard-to-debug issues.
To fix the dependency tree, try following the steps below in the exact order:

  1. Delete package-lock.json (not package.json!) and/or yarn.lock in your project folder.

  2. Delete node_modules in your project folder.

  3. Remove "webpack" from dependencies and/or devDependencies in the package.json file in your project folder.

  4. Run npm install or yarn, depending on the package manager you use.

In most cases, this should be enough to fix the problem.
If this has not helped, there are a few other things you can try:

  5. If you used npm, install yarn (http://yarnpkg.com/) and repeat the above steps with it instead.
     This may help because npm has known issues with package hoisting which may get resolved in future versions.

  6. Check if /Users/home/node_modules/webpack is outside your project directory.
     For example, you might have accidentally installed something in your home folder.

  7. Try running npm ls webpack in your project folder.
     This will tell you which other package (apart from the expected react-scripts) installed webpack.

If nothing else helps, add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
That would permanently disable this preflight check in case you want to proceed anyway.

Learn advanced react and provide feedback on the workshop

Hey folks! I'd love it if some of you could help me out with this workshop and make sure it's good to go! Please just follow the README instructions and let me know where you get stuck and what could be improved. Each of the exercises should be commented well enough for you to get everything done on your own without instruction.

Let me know if there are typos, legit errors, or anything that's unclear.

One thing I know is that the snapshots are failing on codesandbox. Hopefully I can get those working, but it should be working locally :) Thanks!

No solution to extra credit #2

I have a proposed solution that is the following:
In the Toggle Component:

render() {
  return React.Children.map(this.props.children, child => {
    if (typeof child.type === 'function')
      return React.cloneElement(child, {
        on: this.state.on,
        toggle: this.toggle,
      })
    return child
  })
}

In the Usage Component:

return (
  <Toggle onToggle={onToggle}>
    <Toggle.On>The button is on</Toggle.On>
    <Toggle.Off>The button is off</Toggle.Off>
    <Toggle.Button />
    <span>Hello</span>
  </Toggle>
)

Consumers still re-rendering after passing this.state to provider

Hi Kent - I'm having some trouble seeing the optimization discussed in exercise 3 for preventing unnecessary re-renders of the consumers. It could be due to a misunderstanding by me of how those consumers work. To test it out I added a simple counter button that updates the state of the Usage component to trigger a re-render. I also added a console.log within Toggle.Button to check when a rendering happens.

// Flexible Compound Components with context

import React from 'react'
import {Switch} from '../switch'

const ToggleContext = React.createContext();

function ToggleConsumer(props) {
  return (
    <ToggleContext.Consumer>
      {
        (context) => {
          if (!context) {
            throw new Error('Toggle compound components must be rendered within the Toggle component');
          }

          return props.children(context);
        }
      }
    </ToggleContext.Consumer>
  );
}

class Toggle extends React.Component {
  static On = (props) => (
    <ToggleConsumer>
      {({ on }) => on ? props.children : null}
    </ToggleConsumer>
  );
  static Off = (props) => (
    <ToggleConsumer>
      {({ on }) => on ? null : props.children}
    </ToggleConsumer>
  );
  static Button = (props) => {
    return (
      <ToggleConsumer>
        {({ on, toggle }) => {
          console.log('rendering button');

          return <Switch on={on} onClick={toggle} {...props} />
        }}
      </ToggleConsumer>
    );
  }

  toggle = () =>
  this.setState(
    ({on}) => ({on: !on}),
    () => this.props.onToggle(this.state.on),
    )

  state = { on: false, toggle: this.toggle }
  render() {
    // UN-OPTIMIZED
    // return (
    //   <ToggleContext.Provider value={{on: this.state.on, toggle: this.toggle }}>
    //     {this.props.children}
    //   </ToggleContext.Provider>
    // );

    // OPTIMIZED
    return (
      <ToggleContext.Provider value={this.state}>
        {this.props.children}
      </ToggleContext.Provider>
    );
  }
}

class Usage extends React.Component {
  static title = 'Flexible Compound Components';
  state = { count: 0 };

  increment = () => {
    this.setState((prevState) => ({ count: prevState.count + 1}));
  }

  onToggle = (...args) => console.log('onToggle', ...args);

  render() {
    const onToggle = this.props.onToggle || this.onToggle;

    return (
      <React.Fragment>
        <div>{this.state.count}</div>
        <button onClick={this.increment}>+</button>
        <Toggle onToggle={onToggle}>
          <div>
            <Toggle.Button />
          </div>
          <Toggle.On>The button is on</Toggle.On>
          <Toggle.Off>The button is off</Toggle.Off>
        </Toggle>
      </React.Fragment>

    );
  }
}

export {Toggle, Usage as default}

My expectation was that with the optimization of passing this.state I'd no longer see rendering button logged every time I increment my counter. But it still is getting logged. If there is a better forum for this question please let me know!

Running app locally breaks after page refresh

I've cloned the code sandbox as well as this repository to confirm this behavior. After completing the setup and starting the app locally, the pages do not display after hitting refresh in the browser.

node v10.4.0
npm v6.1.0
Linux 4.13.0-45-generic #50~16.04.1-Ubuntu x86_64 GNU/Linux

Control Props with state reducer

Hello!

I'm currently studying this pattern and I was wondering what could be the utility of having a state reducer prop. In this example we are initializing our on state with initial props and telling the user about state changes using onStateChange prop and not using the state reducer at all. I guess the state reducer could be useful to also manage different pieces of state internally. Thus, having controlled and non-controlled properties at the same time. Is this the utility of the pattern?

Thanks for this very useful course.

Running tests is stuck

I'm following your course on code sandbox and I'm stuck at running tests. They're just not running.

screen shot 2018-06-23 at 8 43 17 pm

Component with React.createContext() used in older version of react

Hey Kent,

Awesome workshop!

I am building a similar component using React.createContext(), but I want use the component in an older project that uses react 16.0.0 and errors on createContext because this was introduced later.

Is there any recommended way to polyfill this?

Thank you!

Toggle button's behavior - discrepancy between codesandbox and local

Hello Team,

In codesandbox, the toggle button 'onClick' is expectedly fired on single click where as in my local m/c - which I clone from https://github.com/kentcdodds/advanced-react-patterns-v2.git (tested up to 03.js), it's triggered only on 'double click'. I wonder, what on earth is going on? ๐Ÿ˜•

Note: I'm using Mac Air (and testing on Chrome) and I don't think it's because of the system otherwise I would expect consistent behavior in codesandbox too.

Thanks,
KSM

Are these these patterns mostly for library use

Hello Kent. I have studied and love these react patterns however I barely find a use case for most of them them in my daily work with react but recognise them used all over the place in react libraries.
Is there something i need to know to use these more.

Thanks :)

npm setup failed to compile

Replication Steps

  1. git clone the project
  2. run $ npm run setup --silent
  3. Resulted in: Failed to compile
    Module not found: Error: Can't resolve '@babel/runtime/helpers/esm/inheritsLoose' in '{MY-FOLDER}/github.com/kentcdodds/advanced-react-patterns-v2/node_modules/react-router-dom/esm'

I have checked that there is file under ..node_modules/@babel/runtime/helpers/esm/inheritsLoose.js

Specification

  1. npm version 6.9.0

Kindly help to advise on how to make it successfully compiled, Thanks !

HOC Exercise fails even though my code matches the video

I stumbled upon something. My code for the HOC matches the code in the video, but the tests still fail. The code in /exercises-final is different and passes the tests. Why? Did the hoistNonReactStatics API change?

My code:

function withToggle(Component) {
  const Wrapper = React.forwardRef((props, ref) => {
    return (
      <Toggle.Consumer>
        {(toggleUtils) => (
          <Component {...props} toggle={toggleUtils} ref={ref} />
        )}
      </Toggle.Consumer>
    );
  });
  Wrapper.displayName = `withToggle(${Component.displayName ||
    Component.name})`;
  hoistNonReactStatics(Wrapper, Component);

  return Wrapper;
}

The code above is the exact same code as in the course (FEM) but the tests are still failing. What's going on?

The code in /exercises-final

function withToggle(Component) {
  function Wrapper(props, ref) {
    return (
      <Toggle.Consumer>
        {(toggleContext) => (
          <Component {...props} toggle={toggleContext} ref={ref} />
        )}
      </Toggle.Consumer>
    );
  }
  Wrapper.displayName = `withToggle(${Component.displayName ||
    Component.name})`;
  return hoistNonReactStatics(React.forwardRef(Wrapper), Component);
}

This is what the tests are saying:

image

Test 07 doesn't test for defaultProps

While going through the exercises (which've been amazing!), on exercise 7 I forgot to add the defaultProps, but it still passed the tests, which don't check for that part of the instructions right now.

ErrorCatcher doesn't work on Exercise 6 (Prop Getters)

Hi Kent,

I'm a big fan of your videos.

While doing the Exercise 6 you made a demonstration of how to dismiss the error screen and continue playing with the Final version of the toggle, but locally (I cloned the repo on my computer) nothing is rendered on my screen.

Debugging the code I've found that the error is indeed being caught in componentDidCatch in the ErrorCatcher component but after setting the error in the state, getDerivedStateFromProps is executed and nulling the state again, causing the component to try to render the children again and breaking the screen.

Removing getDerivedStateFromProps does the job for me, but I don't know how it may affect the rest of the application.

Thanks!

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.