Skip to content

Instantly share code, notes, and snippets.

@abernier abernier/index.md
Last active Sep 19, 2019

Embed
What would you like to do?
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);

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 };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.