React snippets

Load SVG image vs. inline SVG

Inline SVG has the advantage of beeing accessible for CSS animation from React. Inline also loads faster. First the img way.

 import myIcon from './relative/path/to/icon.svg'

 // In render method.
 <img src={myIcon} alt="icon" />

 // ...now inline
 import { ReactComponent as MyIcon } from "./icon.svg"

 // In render method.
 <MyIcon /> // or...
 <MyIcon className="someClassThatWillBeUsedInCSS" alt="icon" />
Implement useState with useReducer
const [name, setName] = useReducer((_, value) => value, 'James')
;<input value={name} onChange={(e) => setName(e.target.value)} />
Manually Re-render a Component
const [, rerender] = useState()
rerender({})
//...or...
const [, rerender] = useReducer((x) => x + 1, 0)
rerender()
Pass a Function to use useState
const [count, setCount] = useState(0)
setCount((c) => c + 1)

// Example
const [count, setCount] = useState(0)
useEffect(() => {
  const id = setInterval(() => {
    setCount((c) => c + 1)
  }, 1000)
  return () => clearInterval(id)
}, [])
Define HTML Elements upon use
 const Button = ({ Component = 'button', ...props }) => <Component {...props} />

 <Button>A Button</Button> // Renders a button element
 <Button Component="a">A Link</Button> // Renders an anchor element
React Keys with Fragments
pokemons.map((pokemon) => (
  <React.Fragment key={pokemon}>
    <strong>Name: </strong>
    <span>{pokemon}</span>
  </React.Fragment>
))
Implicit create JSX Elements and nested elements
const element = // JSX
  React.createElement(
    'div',
    null,
    React.createElement(
      'h1',
      {
        className: 'greeting',
      },
      'Hello, world!'
    ),
    React.createElement('p', null, ' lalalalala ')
  )
Cancellable fetch and clean up in react
export default function User({ id }) {
  const [user, setUser] = useState(null)

  useEffect(() => {
    let controller = new AbortController()
    ;(async () => {
      try {
        const response = await fetch(
          `https://jsonplaceholder.typicode.com/users/${id}`,
          {
            signal: controller.signal,
          }
        )
        setUser(await response.json())
        controller = null
      } catch (e) {
        // Handle the error
      }
    })()
    // clean up function
    return () => controller?.abort()
    // add a dependency array
  }, [id])

  return (
    <div>
      {user === null ? (
        <p>Loading user's data ...</p>
      ) : (
        <pre key={user.id}>{user.name}</pre>
      )}
    </div>
  )
}
Bake your own QueryClient (Youtube)

In your client side rendered component you want to cache already fetched data.

function makeQueryClient() {
  const fetchMap = new Map<string, Promise<any>>()
  return function queryClient<QueryResult>(
    name: string,
    query: () => Promise<QueryResult>
  ): Promise<QueryResult> {
    if (!fetchMap.has(name)) {
      fetchMap.set(name, query())
    }
    return fetchMap.get(name)!
  }
}

const queryClient = makeQueryClient()

Then use it inside your component likeā€¦

const pokemon = use(
  queryClient<Pokemon[]>('pokemon', () =>
    fetch('http://localhost:3000/api/pokemon').then((res) => res.json())
  )
)

If you need to drill down more data, the use hook can be conditional

const [selectedPokemon, setSelectedPokemon] = useState<Pokemon>()

const pokemonDetail = selectedPokemon
  ? use(
      queryClient<Pokemon>(['pokemon', selectedPokemon.id].join('-'), () =>
        fetch(`http://localhost:3000/api/${selectedPokemon.id}`).then((res) =>
          res.json()
        )
      )
    )
  : null
useImperativeHandle to merge forward ref with internal ref

If the ref is forwarded from the parent element you cannot use it without merging is somehow. Here is how to do it with useImperativeHandle.

In the React documentation useImperativeHandle is used to expose selected nested element functionality.

function App() {
  const [text, setText] = useState('Fun')
  const fancyRef = useRef()

  const submitButton = () => {
    setText(fancyRef.current.value)
  }

  return (
    <div id='App'>
      <p>Submitted Text from forwardRef: {text}</p>
      {/* This ref is forwarded directly to the DOM element designated by FancyTextSubmit */}
      <FancyTextSubmit ref={fancyRef} onClick={submitButton} />
    </div>
  )
}

const FancyTextSubmit = forwardRef(({ onClick }, forwardRef) => {
  const inputRef = useRef()
  useImperativeHandle(forwardRef, () => inputRef.current)
  const onButtonClick = (e) => {
    onClick(e)
    // `current` points to the mounted text input element
    inputRef.current.focus()
  }

  return (
    <div>
      <input ref={inputRef} type='text' />
      <button onClick={onButtonClick}>Submit</button>
    </div>
  )
})