Conditionally render components based on the browser size rather than rendering and hiding the components with CSS. Taken from @cassidoo's post Building a custom React media query hook for more responsive apps
import { useState, useEffect } from 'react';
export function useMediaQuery(query) {
const [matches, setMatches] = useState(false);
useEffect(() => {
const media = window.matchMedia(query);
if (media.matches !== matches) {
setMatches(media.matches);
}
const listener = () => {
setMatches(media.matches);
};
media.addListener(listener);
return () => media.removeListener(listener);
}, [matches, query]);
return matches;
}
// how to use it
function Page() {
let isPageWide = useMediaQuery('(min-width: 800px)');
return (
<>
{isPageWide && <UnnecessarySidebar />}
<ImportantContent />
</>
);
}
A very basic example of how we can pass props down to props.children. If you're wanting to abstract away some logic, make your code more readable or make it easy to switch out components, this is a great solution.
// inside our component we add the props we want as arguments for props.children
const Blocks = ({ allBlocks, children }) =>
allBlocks.map((block, index) => <div>{children(block, index)}</div>);
// then we can access those arguments via a function
<Blocks allBlocks={state.allBlocks}>
{(block, index) => {
return <DynamicBlock block={block} index={index} />;
}}
</Blocks>;
Create a Textarea that auto resizes as you add more content. It makes for a much nicer experience.
export const TextArea = ({
label,
name,
defaultValue,
rows = 5,
}: TextAreaProps) => {
const textarea = useRef<HTMLTextAreaElement>(null)
const [characterCount, setCharacterCount] = useState(
defaultValue?.length || 0,
)
// if we change the line height in css make sure to change this
let lineHeight = 1.75
let initialLimit = rows * (lineHeight * 16)
const handleChange = (e: React.ChangeEvent<any>) => {
let scrollLeft =
window.pageXOffset ||
(document.documentElement || document.body.parentNode || document.body)
.scrollLeft
let scrollTop =
window.pageYOffset ||
(document.documentElement || document.body.parentNode || document.body)
.scrollTop
e.target.style.height = 'auto'
e.target.style.height = `${Math.max(e.target.scrollHeight, initialLimit)}px`
window.scrollTo(scrollLeft, scrollTop)
}
useEffect(() => {
if (textarea.current) {
textarea.current.style.height = 'inherit'
textarea.current.style.height = `${Math.max(
textarea.current.scrollHeight,
initialLimit,
)}px`
}
}, [])
return (
<div className="flex flex-col gap-2 w-full relative">
<label htmlFor={name}>{label}</label>
<textarea
ref={textarea}
className="border-slate-300 border w-full p-3 text-black leading-7 rounded text-base resize-none overflow-hidden disabled:bg-gray-100 disabled:text-gray-400 disabled:cursor-not-allowed"
name={name}
id={name}
rows={rows}
defaultValue={defaultValue}
spellCheck={true}
onChange={(e) => {
handleChange(e)
}}
></textarea>
</div>
)
}