но почему его почти не используют ?
А на основе чего такой вывод? Мне показалось наоборот, всякую оптимизацию используют везде, даже там где она делает только хуже.
(без собственного состояния)
Внутренний стейт компонента не влияет на результат работы своего memo, memo сравнивает только пропсы.
По логике вещей каждый компонент (без собственного состояния), даже который не использует props, должен быть обернут в memo, но так не делают, почему?
Тут есть условности. У меня например вот такие правила:
Оборачиваем в memo обязательно, если - родительский компонент часто перерендеривается без изменений пропсов вашего компонента. Если ваш компонент не обернуть в memo, то он будет столько же перерендериваться, сколько и родительский. Но тут я бы обернул ваш компонент в родительском в useMemo (если на хуках писать).
Не оборачиваем в memo, т.к. если обернуть, это ничего не даст или сделает хуже, если - родительский компонент перерендеривается только при изменении пропсов, которые передаются в ваш компонент. Другими словами, если ваш компонент перерендеривается из-за родителя только тогда, когда меняются значения его пропсов, то memo будет проверяться зря (а memo тоже тяжелый).
Можно обернуть в memo, если - компонент рисует сложную верстку с большим количеством других компонентов, и имеет сложный код в рендере или в useEffect (без зависимостей, который выполняется на каждый рендер).
В остальных случаях можно не использовать memo, если на то не указывают исследования производительности конкретно вашего приложения.
Еще важно следить за перерендерами, чтобы родитель не передавал пропсы, у которых на каждом рендере разная ссылка, пример:
<MemoComp onClick={() => console.warn('hello')} />
в таком случае, memo не будет работать. Это можно еще случайно пропустить, если не используете TypeScript/Flow, то вот такой код
<MemoComp isActive={item || isEnabled} />
будет перерендериваться лишний раз, если вдруг окажется, что item это объект с нестабильной ссылкой.
В общем, главное понимать, что простой memo быстрее простого рендера, нужно просто не допустить двойную работу, когда при любом рендере будет сравниваться memo и происходить рендер.