Preload image
useEffect(() => { setTimeout(() => { // preload const img = new Image(); img.src = image; // setLoaded to true on load and display image img.onload = () => { setLoaded(true); }; }, (idx + 1) * 300); }, []); ... loaded ? ( // display image )
React: Note on what happens during rendering and re-rendering
- this is a note on what goes on when a component renders and re-renders
- notes are from watching React Render Tutorial - YouTube
Rendering has 2 phases: Initial Render: Render phase: -start at root -goes down leaf components -use createElement() to convert jsx to react elements
Commit phase: -all react elements are handed to commit phase and are applied to the DOM Rerender: Render phase: -search all components that have been flagged as needing updates (useState setState method, useReducer dispatch method) -convert flagged components to react elements -compare previous virtual DOM to new virtual DOM -if components convert to same element as previous then discarded
Commit phase: -all the changed elements are handed to commit phase and are applied to the DOM
useState * The setter function from a useState hook will cause the component to re-render. * The exception is when update a State Hook to the same value as the current state. -Same value after initial render? component will not re-render. - Same value after re-render? React will render that specific component one more time but will be discarded before going to commit phase
useReducer * The dispatch function from a useReducer hook will cause the component to re-render. * The exception is when update a State Hook to the same value as the current state. -Same value after initial render? component will not re-render. -Same value after re-render? React will render that specific component one more time but will be discarded before going to commit phase
State Immutability * Mutating an object or an array as state will not cause a re-render when used with the useState or useReducer hook * To re-render, make a copy of the existing state, modify as necessary and then pass the new state to the setter function or while returning from a reducer function
Parent & Child * When parent component re-renders, all child components re-render * New state same as old state after initial render? Both parent and child do not re-render * New state same as old state after re-render? Parent re-renders one more time but child never re-renders * Child components re-rendering but not affecting the DOM is “unnecessary render”
Same element reference -To avoid “unnecessary renders”, * extract the child component and pass it down as a prop of the parent component (as children element) * Whenever there is a re-render caused by a change in the state of the parent component, React will optimize the re-render for you by knowing that the props has to be referencing the same element before and after the render
React Memo * In React, when a parent component renders ,a child component might unnecessarily render. * To optimize this behavior, you can use React.memo and pass in the child component. * React.memo will perform a shallow comparison of the previous and new props and re-render the child component only if the props have changed.
Incorrect React Memo -React.Memo in child component for all cases -when parent component re-renders for all cases ・Parent Child - If the child component has children elements as props, child component will re-render even with React.Memo because children elements are always a new reference ・Impure component - Even if the child component has a variable that can change (date, random, etc) the child component will not re-render because of React.Memo ・Prop reference -If child component has objects or functions as props from parent component, child component will always re-render even with React.Memo because every time the parent component re-renders, new objects and functions are created.
React: Simple context template
import React, { createContext, Dispatch, useContext, useReducer } from "react" const hogeData = {}; export const HogeContext = createContext<any>(hogeData) export const HogeDispatchContext = createContext<Dispatch<any>>(() => { }) export const HogeContextProvider: React.FC = ({ children }) => { const [state, dispatch] = useReducer((_: any, action: any) => { return action; }, hogeData) return ( <HogeContext.Provider value={state}> <HogeDispatchContext.Provider value={dispatch}> {children} </HogeDispatchContext.Provider> </HogeContext.Provider> ) }
Regex: match one byte character and number
event.target.value.match(/^[A-Za-z0-9]+$/)
Javascript: Skip an element array and make a new array
var newArray = array.reduce(function(result, hoge) { if (some condition) { result.push(hoge); } return result; }, []);
or
var newArray = array.filter(function(hoge) { if (some condition) { return hoge; } });
React: Outside Click Detection
import React, { useRef, useEffect } from "react"; export default SomeFunctionComponent(props) { const elementRef = useRef(null); useEffect(() => { function handleOutsideClick(event) { if (ref.current && !ref.current.contains(event.target)) { do something } } document.addEventListener("mousedown", handleOutsideClick); return () => { // Unbind the event listener on clean up document.removeEventListener("mousedown", handleOutsideClick); }; }, [elementRef]); } return ( <div ref={elementRef}>{props.children}</div>; ) }
React Context API examples
*context api example for me, myself, and i
2 ways to use context api with inital value
hoge.contex.jsx import { createContext } from ‘react’ import HOGE_DATA from ‘./hoge.data.js’ // some data with values const HogeContext = createContext(HOGE_DATA) export default HogeContext
1 using Context.Consumer
foo.jsx import HogeContext from ‘hoge.context.jsx’ <HogeContext.Consumer> { data => { const hogeData = data[hoge] const { foo, blah } = hoge return ( use the destructure data as arguments ) } } </HogeContext.Consumer>
2 useContext
foo.jsx import { useContedt } from ‘react’ const data = useContext(HogeContext) const hogeData = data[hoge] const { foo, blah } = hogeData return ( <div className=‘foo’>{foo}/> <div className=‘blah’>{blah}/> )
To dynamically set values to context
hoge.context.jsx import { createContext } const HogeContext = createContext(undefined) export default HogeContext
foo.jsx import { useContext } from ‘react’ import { HogeContext } from ‘hoge.context’ const foo = { bool: true, method : () => concsole.log(“blah”); } <HogeContext.Provide value={foo}r> <Component /> <HogeContext.Provider>
component.jsx import { useContext } from ‘react’ import HogeContext from ‘hoge.context’ const { bool, method } = useContext(HogeContext)
but this is bad practice so....
make context with initial values and pass local values
hoge.context.jsx import { createContext } const HogeContext = createContext({ bool: true, method: () => {} }) export default HogeContext
foo.jsx import { useState, useContext } from ‘react’ import { HogeContext } from ‘hoge.context’ const [bool, setBool] = useState(true) const method = () => setBool(!bool) <HogeContext.Provide value={{ bool, method, }}r> <Component /> <HogeContext.Provider>
component.jsx import { useContext } from ‘react’ import HogeContext from ‘hoge.context’ const { bool, method } = useContext(HogeContext)
or create a provider
hoge.provider.jsx import React, { createContext, useState, useEffect } from 'react'; import { addItemToHoge, removeItemFromHoge, HogeItem, totalHogeItem, totalHogePrice, } from ‘./hoge.utils.js'; export const HogeContext = createContext({ hidden: true, toggleHidden: () => {}, hogeItems: [], addItem: () => {}, removeItem: () => {}, clearItemFromHoge: () => {}, hogeItemsCount: 0, totalPrice: 0, }); const HogeProvider = ({ children }) => { const [hidden, setHidden] = useState(true); const [hogeItems, setHogeItems] = useState([]); const [hogeItemsCount, setHogeItemsCount] = useState(0); const [totalPrice, setTotalPrice] = useState(0); const addItem = (item) => setHogeItems(addItemToHoget(hogeItems, item)); const removeItem = (item) => setHogeItems(removeItemFromHoge(hogeItems, item)); const clearItemFromHoge = (item) => setHogeItems(clearItem(hogeItems, item)); const toggleHidden = () => setHidden(!hidden); useEffect(() => { setHogeItemsCount(totalHogeItem(hogeItems)); setTotalPrice(totalHogePrice(hogeItems)); }, [hogeItems]); return ( <HogeContext.Provider value={{ hidden, addItem, toggleHidden, hogeItems, removeItem, clearItemFromHoge, hogeItemsCount, totalPrice, }} > {children} </HogeContext.Provider> ); }; export default HogeProvider
index.js import HogePorvider from ‘’hoge.provider’ <HogeProvider> <App/> <HogeProvider>