Skip to content

Instantly share code, notes, and snippets.

@lxsmnsyc
Last active January 4, 2021 10:28
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 lxsmnsyc/7eae812f6b4a6a0825ebcc11cd43be1e to your computer and use it in GitHub Desktop.
Save lxsmnsyc/7eae812f6b4a6a0825ebcc11cd43be1e to your computer and use it in GitHub Desktop.
demo-1

Preferred CSS/Design

Tailwind

Pros

  • When customizing stick to the design system
  • Small learning curve
  • They have component-based design in mind
  • Upcoming NextJS, built-in Tailwind
  • CSS Purging
  • Stateful classes
  • ui-devtools (still needs to hit the dono goal)
<div
  className="dark:lg:display-block:hovered sm:display-none"
>
  Hello World
</div>

Cons

  • Too constraining
  • Accessibility (?)
  • className length

Stitches

Pros

  • Variants
  • Easier to transition from Base Web or Styletron
  • Token-based theming

Cons

  • Theme customization
  • Beta stage

Styled JSX

Pros

  • Built-in NextJS

Cons

  • Style overrides (specificity)
  • Not DRY-applicable

twin.macro

Pros

  • Same semantics as Tailwind
  • Custom property (className )
import tw from 'twin.macro'

const Input = tw.input`border hover:border-black`

// Stateful
import tw, { styled } from 'twin.macro'

const Input = styled.input(({ hasHover }) => [
  `color: purple;`,
  tw`border rounded`,
  hasHover && tw`hover:border-black`,
])
const Component = () => <Input hasHover />

import 'twin.macro'

const Input = () => <input tw="border hover:border-black" />

Chakra

Pros

  • Tools
  • Customization by props
  • ARIA
  • Variants
  • Same semantics as Base Web
  • Similar to Stitches on theming

Cons

  • Too many components
  • Suspense
  • HOCs (lazy, memo)
  • Hooks
  • Concurrent Mode
  • Fiber Architecture

Fiber Architecture

  • Title - parent node

    • h1
      • Hello World
  • It would render the whole app, then create VDOM tree from the render output, then connect to real DOM tree.

  • Adapted by Vue, Elm, Hyper, etc.

  • Problem is it blocks the main thread process.

  • Two phases: Render phase and commit phase

  • Render phase, not eager, it gives time for higher-priorirty process to happen.

  • Once render phase, commit phase happens.

  • Render phase: render function (functional components or render method of classes), constructors

  • Commit phase: Lifecycle methods (componentDidMount) and effect hooks (useEffect and useLayoutEffect)

useEffect(() => {
  const listener = () => {
    setState((current) => {
      if (!is(current, store.getValue())) {
        return store.getValue();
      }
      return current;
    });
  };

  // Let's assume that the state has changed at this point
  listener();

  // Further updates
  const unsubscribe = subscribe(listener);

  return unsubscribe;
}, [store, subscribe])

Concurrent Mode

  • render per component, commit immediately
  • hydration
  • getServerSideProps -> renderToHTML -> hydrate (connect pre-rendered tree to the initial VDOM tree)
ReactDOM.render(<App />, document.getElementById(root));

const root = ReactDOM.createRoot(document.getElementById(root));

root.render(<App />)

Suspense

const { data, error } = useSWR(`/api/user`);

render-then-fetch

const [data, setData] = useState();
const [error, setError] = useState();

useEffect(() => {
  fetcher().then(setData, setError);
}, []);

return { data, error };
function UserDetails() {
  // ???
  const userDetails = userDetailsFetcher.read();

  return (
    <>
      <h1>{userDetails.name}</h1>
      <h1>{userDetails.age}</h1>
    </>
  );
}

<Suspense fallback={<h1>Loading</h1>}>
  <UserDetails />
</Suspense>

Hooks

useRef

  • memorize a single value/reference for the whole lifecycle
  • refs are not reactive.
  • capturing DOM

useState

  • states
  • reactive
  • bail-out mechanism

useReducer

const [count, dispatch] = useReducer((state, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}, 0);

useEffect

  • useEffect != componentDidMount
  • Always ideal for side-effects
  • Only runs once on strict mode and concurrent mode
  • useEffect always runs after useLayoutEffect

useLayoutEffect

  • useLayoutEffect == componentDidMount
useLayoutEffect(() => {
  inputRef.current.addEventListener('click', listener);
}, []);

<input ref={inputRef}>

useDebugValue

  • Presents debug value on devtools

useImperativeHandle

  • Receives the forwarded ref, decorates value
const Input = forwardRef((props, ref) => {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    value: inputRef.current.value,
  }));
});

useMemo

  • memoizes a value from a function
  • recomputes when dependencies change
  • unstable
useConstant(expensiveFunc);
const value = useMemo(expensiveFunc, []);

useCallback

  • unstable
<div onClick={() => {
  // ...
}}>

useContext

const Example = createContext({ a: 'Hello', b: 'World' }, (prev, next) => {
  if (prev.a !== next.a) {
    return 0b01;
  }
  if (next.b !== prev.b) {
    return 0b10;
  }
  return 0b00;
});

//
const { a } = useContext(Example, 0b01);

// 
const value = useContext(Example, (state) => newState);

useOpaqueIdentifier

useMutableSource

useTransition

useDeferredValue

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