I'm trying to create a custom hook that will keep the text on one line, this is what I've got so far:
import { useEffect, useState, useRef } from "react";
export default function useOneLineText(initialFontSize, text) {
const containerRef = useRef(null);
const [adjustedFontSize, setAdjustedFontSize] = useState(initialFontSize);
useEffect(() => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const containerWidth = containerRef.current.getBoundingClientRect().width;
let currentFontSize = initialFontSize;
do {
ctx.font = `${currentFontSize}px "Lato"`;
currentFontSize -= 1;
} while (containerWidth < ctx.measureText(text).width);
setAdjustedFontSize(currentFontSize);
}, []);
return { containerRef, adjustedFontSize, text };
}
And the usage:
import React, { useState } from "react";
import "./style.css";
import useOneLineText from "./useOneLineText";
const initialFontSize = 32;
export default function App() {
const [shortText, setShortText] = useState("Hello Peaceful World!");
const { containerRef, adjustedFontSize, text } = useOneLineText(
initialFontSize,
shortText
);
return (
<div>
<h1
ref={containerRef}
style={{ width: "100px", fontSize: `${adjustedFontSize}px` }}
>
{text}
</h1>
<h1 style={{ width: "100px", fontSize: `${initialFontSize}px` }}>
Hello Cruel World!
</h1>
<button onClick={() => setShortText("Hello World!")}>Remove Peace</button>
</div>
);
}
I was wondering why is my font not updating when trying to change the text with the Remove Peace
button. I'm also not sure if looping inside useEffect and decreasing the font size by 1 is the best way to go, is it possible to calculate the adjusted font size without the loop? Here is my working example.