DEV Community

Juraj Pavlović for Bornfight

Posted on

React Hooks cheat sheet

Not so long ago I started working with functional components instead of class based ones. The main goal was to learn how to implement React Hooks inside them. This way we can write less code and make it more reusable.

The benefits of using hooks and functional components are reusability, simpler & shorter code and the simplicity of testing those components.

The usual class approach of things is now a thing of the past. And here I will share short and understandable react hooks cheat sheet. This is not a tutorial for hooks as there are many articles online and the docs are really good. This serves as a quick reference for people already somewhat familiar with writing hooks. If you are new to hooks, you can still take a look. With that said, let's begin.

UseState - similar to React state and setState

  • with primitive value
const App = () => {
    const [carSpeed, updateCarSpeed] = useState(10);
    return (
        <div>
            <p>Car is going {carSpeed} km/h</p>
            <button onClick={() => updateCarSpeed(carSpeed + 5)}>
                Speed up
            </button>
        </div>
    );
};
Enter fullscreen mode Exit fullscreen mode
  • with object
export const App = () => {
    const [carForm, updateForm] = useState({});
    const updateField = (e) => {
        updateForm({ ...carForm, [e.target.name]: e.target.value });
    };

    const handleSubmit = (e) => {
        e.preventDefault();
        console.log(carForm);
    };
    return (
        <form onSubmit={handleSubmit}>
            <label>
                Car Owner:
                <input
                    value={carForm.owner}
                    name="owner"
                    onChange={updateField}
                />
            </label>
            <br />
            <label>
                Car model:
                <input
                    value={carForm.model}
                    name="model"
                    onChange={updateField}
                />
            </label>
            <button>Submit</button>
        </form>
    );
};
Enter fullscreen mode Exit fullscreen mode

UseEffect - similar to componentDidUpdate

  • only triggers once (because of empty array param)
export const App = () => {
    const [carsData, updateCars] = useState({});

    useEffect(() => {
        fetch("http://example.com/cars.json")
            .then((resp) => resp.json())
            .then((data) => {
                updateCars(data);
            });
    }, []);

    const renderCars = () => {
        return carsData.cars.map((car) => {
            <p key={car.id}>{car.name}</p>;
        });
    };

    return <div>{renderCars()}</div>;
};
Enter fullscreen mode Exit fullscreen mode
  • trigger on carName variable change
export const App = () => {
    const [carName, updateCarName] = useState("");

    useEffect(() => {
        console.log("changed");
    }, [carName]);

    return (
        <div>
            <input
                value={carName}
                onChange={(e) => updateCarName(e.target.value)}
            />
        </div>
    );
};
Enter fullscreen mode Exit fullscreen mode

UseReducer with React.memo HOC and useCallback

  • This example makes use of useReducer hook which acts similar to Redux. It has a reducer and actions that change the state in the reducer. We also make use of the React.memo and useCallback for the sole reason of not re-rendering new "Car" components when each car is checked that it is sold.
  • UseCallback - this hook is used when you have a component with a frequently re-rendering child and to which you pass a callback to. Without it the addCar function would be re-instantiated each time a new car is added to the list.

// initial cars state
const initialState = [
  {
    id: id(),
    name: "Audi A4",
    description: 'Black tint with red wheels, 100kw',
    sold: false
  },
  {
    id: id(),
    name: "Porsche 911",
    description: 'Cherry red tint with dark golden wheels, 300kw',
    sold: false
  },
  {
    id: id(),
    name: "Lamborghini Gallardo",
    description: 'Lamborghini green with black wheels, 500kw',
    sold: false
  },
];


// action names
const CAR_ADD = 'CAR_ADD';
const CAR_SELL = 'CAR_SELL';

// the reducer
const reducer = (state, action) => {
  if (action.type === CAR_ADD) {
    return [action.payload, ...state];
  }

  if (action.type === CAR_SELL) {
    return state.map(car => {
      if (car.id !== action.payload.id) {
        return car;
      }
      return { ...car, sold: !car.sold };
    });
  }

  return state;
};

const App = () => {
  const [cars, dispatch] = useReducer(reducer, initialState);

  const addCar = useCallback(({ name, description }) => {
    dispatch(
      {
        type: CAR_ADD,
        payload: {
          name,
          description,
          sold: false,
          id: id()
        }
      },
      [dispatch]
    );
  });

  const toggleSold = useCallback(
    id => {
      dispatch({
        type: CAR_SELL,
        payload: {
          id
        }
      });
    },
    [dispatch]
  );

  return (
    <div style={{ maxWidth: 400, margin: '0 auto' }}>
      <NewCarForm onSubmit={addCar} />
      <Cars cars={cars} onSell={toggleSold} />
    </div>
  );
};

const Cars = ({ cars = [], onSell }) => {
  return (
    <div>
      <h2>Cars ({cars.length})</h2>
      {cars.map(car => (
        <Car key={car.id} car={car} onSell={onSell} />
      ))}
    </div>
  );
};

const Car = React.memo(({ car, onSell }) => {
  return (
    <div style={{border:"1px solid", margin: 10, padding: 10}}>
      <h3>{car.name}</h3>
      <p>{car.description}</p>
      <div>
        <label>
          <input
            type="checkbox"
            checked={car.sold}
            onChange={() => onSell(car.id)}
          />
          Sold
        </label>
      </div>
    </div>
  );
});

const NewCarForm = React.memo(({ onSubmit }) => {
  const [name, setCarName] = useState('');
  const [description, setCarDescription] = useState('');

  const handleChange = e => {
    e.preventDefault();
    onSubmit({ name, description });
  };

  return (
    <form onSubmit={handleChange}>
      <input
        placeholder="Car name"
        type="text"
        value={name}
        onChange={event => setCarName(event.target.value)}
      />
      <input
        placeholder="Car description"
        type="text"
        value={description}
        onChange={event => setCarDescription(event.target.value)}
      />
      <input type="submit" />
    </form>
  );
});
Enter fullscreen mode Exit fullscreen mode

That would be all, thank you for reading kind stranger. Do you have something of your own to add to the list? Let me know.

Top comments (9)

Collapse
 
guico33 profile image
guico33
const App = () => {
    const [carSpeed, updateCarSpeed] = useState(10);
    return (
        <div>
            <p>Car is going {carSpeed} km/h</p>
            <button onClick={() => updateCarSpeed(carSpeed + 5)}>
                Speed up
            </button>
        </div>
    );
};

Enter fullscreen mode Exit fullscreen mode

Every time the next state is based on the existing one, better use the callback version of the state updater. Here it would be updateCarSpeed(prevCarSpeed => prevCarSpeed + 5).

Collapse
 
jurajuki profile image
Juraj Pavlović

I will be glad to use the callback version. Thank you for the advice. Do you mind explaining in more detail, why exactly is it better to use the callback version?

Collapse
 
maciekgrzybek profile image
Maciek Grzybek

I think it's similar to setState in the class components - you can be sure that you're updating the correct value, am I right @guico33 ?

Thread Thread
 
wilomgfx profile image
William Cantin

Yes

Collapse
 
vadorequest profile image
Vadorequest

If you're interested to see more functional components with TypeScript, check out our recent github.com/UnlyEd/next-right-now OSS release. We also prefer functional components over classes, and thus hooks over HOC.

Collapse
 
josipreh profile image
Josip Reh

Great cheat sheet!

Also there is a typo in the second object example.
I guess you wanted to call updateForm instead of updateField in the updateField function

Collapse
 
jurajuki profile image
Juraj Pavlović

Oh thank you!
Nice observation, I indeed did wanted to call updateForm. Fix coming right up :)

Collapse
 
maciekgrzybek profile image
Maciek Grzybek

Nice article Juraj :)

Collapse
 
jurajuki profile image
Juraj Pavlović

Have my gratitude :)