Skip to content

Instantly share code, notes, and snippets.

@abernier
Last active April 2, 2022 04:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abernier/8dd1b6d1418d81d527d88ac2690085fc to your computer and use it in GitHub Desktop.
Save abernier/8dd1b6d1418d81d527d88ac2690085fc to your computer and use it in GitHub Desktop.
React cheatsheet

Custom hooks

function useTimeout(ms = 0) {
  const [ready, setReady] = React.useState(false);
  
  React.useEffect(function () {
    const int = setTimeout(() => setReady(true), ms);
    
    return () => clearTimeout(int);
  }, [ms]);
  
  return ready;
}

function Demo(props) {
  const done = useTimeout(2000);
  
  return (
    <div>
      {done ? "DONE" : "WAITING"}
    </div>
  );
}

jsx

Conditional

{god ? (
  {/* some jsx */}
) : (
  {/* other jsx */}
)}

setState as callback function

this.setState(state => ({
  products: [...state.products, {name: 'NEW product'}]
}));

"Slots"

Also known as containment

function Popin(props) {
  return (
    <div className="Popin">
      <div className="Popin__left">
        {props.left}
      </div>
      <div className="Popin__right">
        {props.right}
      </div>
    </div>
  );
}

function App() {
  return (
    <Popin
      left={
        <Contacts />
      }
      right={
        <Chat />
      } />
  );
}

HOC

With Higher-order components, you create a function that takes in a component as its argument. From that function, you return a new component that encapsulates all of the shared logic and renders the component that was passed in. From there, you can pass any data to the rendered component via props.

-- Tyler McGinnis

function withHover(Component) {
  return class extends React.Component {
    state = {hovering: false};
    
    handleHover = (e) => {this.setState({hovering: true})}
    handleOut = (e) => {this.setState({hovering: false})}
    
    render() {
      return (
        <div onMouseOver={this.handleHover} onMouseOut={this.handleOut}>
          <Component hovering={this.state.hovering} {...this.props} />
        </div>
      );
    }
  }
}

// Call with:
const HoverButton = withHover(Button);

HOC with function-component

function withAuth(Component) {
  return function AuthHOC(props) {
    const { user } = useAuth()

    if (user === false) return "you need to be logged in"

    return <Component {...props} />
  }
}

NB: 🧠 convoluted technique... Prefer using hooks

React.useState

see: https://reactjs.org/docs/hooks-reference.html#usestate

const [clicks, setClicks] = useState(0); // preserve values between renders
const [clicks, setClicks] = useState(() => fibonacci(500)); // expensive initialization through a function
setClicks(clicks => click+1) // cannot just setClicks(clicks+1)

React.useEffect

see: https://reactjs.org/docs/hooks-reference.html#useeffect

useEffect(() => {
  // executed after any render (after render is painted to the screen)
})
useEffect(() => {
  // executed after initial-render + after any render when `loggedin` changes
}, [loggedin])
useEffect(() => {
  // executed after initial-render + after any render when `loggedin` OR `props.message` change
}, [loggedin, props.message])
useEffect(() => {
  // executed after the initial-render
}, [])

cleanup

useEffect(() => {
  // 
  return () => {
    // executed before any rerender (rerender = any but not the first one)
  }
})
const [loggedin, setLoggedin] = useState(false);

useEffect(() => {
  // 
  return () => {
    // executed before any rerender but only if `loggedin` has changed
  }
}, [loggedin])

useRef

function Timer() {
  const intRef = useRef();

  useEffect(() => {
    const id = setInterval(() => {
      // ...
    });
    intRef.current = id;
    return () => {
      clearInterval(intRef.current);
    };
  });

  // ...
}

useTheme

import React from "react";

const ThemeContext = React.createContext();

const themes = ["dark", "light"];

const initialState = {
  name: "dark"
};

function reducer(state, action) {
  switch (action.type) {
    case "change":
      if (themes.indexOf(value) !== -1) {
        throw new Error("This theme `${action.value}` does not exist");
      }
      return {
        ..state,
        name: value
      };
    case "reset":
      return {
        ...initialState
      };
    default:
      throw new Error(`This action: ${action.type} is not supported`);
  }
}

// A new component that wraps children and allow them to consume the same reducer (complex state)
export default props => {
  const [state, dispatch] = React.useReducer(reducer, initialState);

  const value = [state, dispatch]; // `value` is what useTheme() function will return/expose
  return (
    <ThemeContext.Provider value={value}>
      {props.children}
    </ThemeContext.Provider>
  );
};

// Defining a `useTheme` hook that will consume the provided context
function useTheme() {
  return React.useContext(ThemeContext); // will return `value` to any component that `useTheme()`
}
export { useTheme };

useAuth

see: https://codesandbox.io/s/trusting-dijkstra-bj5le

withAuth

Instantiate a Auth provider once,

Then apply withAuth to any component you want to have access to props.auth

see: https://codesandbox.io/s/cool-rgb-s0wvx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment