const [selected, setSelected] = useState('all');
let filterdTodos;
switch(selected) {
case 'all':
filterdTodos = todos;
break;
case 'checked':
filterdTodos = todos.filter(t => t.checked);
break;
case 'notChecked':
filterdTodos = todos.filter(t => !t.checked);
break;
}
const [selected, setSelected] = useState('all');
const filterdTodos = useMemo(() => {
switch(selected) {
case 'all':
return todos;
case 'checked':
return todos.filter(t => t.checked);
case 'notChecked':
return todos.filter(t => !t.checked);
}
}, [selected, todos])
<select className="todos__filter" onChange={(event) =>setSelected(event.target.value)}>
...
{filterdTodos.map(...)}
import img from './assets/img.jpeg'
public
и брать их как есть по прямым путям относительно корня без всяких хэшей.useMemo
нужен, чтобы при передаче значения как prop
в низлежащий memo
компонент не происходила перерисовка оного если не было изменений(+при передаче как зависимость в другой хук, тот не срабатывал заново).useMemo
и пойдёт водопадом перерисовка на каждый чих каждого компонента по всему дереву вниз. И именно это является основной причиной тормозов в React, а не какие-то там мифические сложные вычисления.useMemo
"только в узких местах" и нигде больше. Прикол в том, что с таким подходом при разрастании проекта никакого "узкого места" просто нет, тормозить начинает просто потому, что складываются тысячи микротормозов от тысяч перерисовок тысяч компонентов: наступает то самое "потом" и тут придётся переписывать с useMemo
чуть ли не весь проект, чтоб снизить эти тормоза.useMemo
стараются таки использовать заранее в каждом месте, где оно потенциально нужно. Некоторые радикальные философии вообще предполагают использование useMemo
просто всегда, без исключений.:) const lines = [1, 2, 3];
return lines.map(line => (
<p> {line} </p>
));
function Component() {
const [lines, setLines] = useState([1, 2, 3]);
const addLine = useCallback(() => {
setLines(lines => [...lines, lines.length+1])
});
return(
<>
<button onClick={addLine} className="button">
addLine
</button>
{lines.map(line => (
<p> {line} </p>
))}
</>
}
setTimeout
(тут я обернул его в Promise
для простоты и наглядности):const delay = (ms) => new Promise(r => setTimeout(r, ms))
function Component() {
const [lines, setLines] = useState([]);
const addLines = useCallback(async () => {
let i = 0;
while(i++ < 10) {
await delay(1000);
setLines(lines => [...lines, i])
}
});
return(
<>
<button onClick={addLines} className="button">
addLine
</button>
{lines.map(line => (
<p> {line} </p>
))}
</>
);
}
function useState(initialValue) {
// подсчитываем вызовы useState в компоненте
component.useStateCount++;
// если уже был вызов этого useState(т.е. это не первая отрисовка)
if (component.useStateCount in component.useStateCache)
// возвращаем результат из кэша
return component.useStateCache[component.useStateCount];
// если первый вызов - подготавливаем ответ вида [state, setState]
const useStateResult = [
initialValue,
function setState(callbackOrValue) {
// если аргумент setState - функция
if (typeof callbackOrValue === 'function') {
// вызываем её с предыдущем значением в качестве аргумента и присваиваем результат вызова в state
useStateResult[0] = callbackOrValue(useStateResult[0]);
} else {
// иначе просто присваиваем аргумент в state
useStateResult[0] = callbackOrValue;
}
// вызов обновления компонента
component.updateComounent();
}
];
// добавляем в кэш
component.useStateCache[component.useStateCount] = useStateResult;
// возвращаем
return useStateResult;
}
[class^="chat__root__"]
. Заметьте я использовал не полное имя класса, а только начало и модификатор ^=
указывающий сверять только начало(если класс не первый, то можно использовать *=
). Почему? Потому что "непонятные буковки" в конце - это генерируемый при сборке хэш, который поменяется при выпуске следующей версии фронта и если вы к нему привяжитесь - ваш скрипт очень скоро перестанет работать.// @run-at document-start
function addCss(css, root = window) {
const style = root.document.createElement('style');
style.innerHTML = css;
(root.document.head || root.document.documentElement).append(style);
return style;
}
const css = `
[class^="chat__root__"] {
dislpay: none !important;
}
`;
addCss(css);
// @run-at document-start
const css = `
[class^="chat__root__"] {
dislpay: none !important;
}
`;
// отлавливаем загрузку фреймов
new MutationObserver(() => {
document.querySelectorAll('iframe:not([us-processed]').forEach((iframe) => {
if (isAccessibleFrame(iframe)) {
// добавляем наш css
addCss(css, iframe.contentWindow);
// на случай если содержимое фрейма перепишут позднее
iframe.addEventListener('load', () => addCss(css, iframe.contentWindow));
}
// помечаем что обработали этот фрем, чтоб не повторять
iframe.setAttribute('us-processed', true);
});
}).observe(document, {childList: true, subtree: true});
// проверяем что содержимое фрейма доступно
function isAccessibleFrame(iframe) {
try {
iframe.contentWindow.test
return true
} catch (e) {
return false
}
}
Swiper
не ждёт свойства spaceBetween
. Вы уверены, что оно хоть что-то делает?Swiper
и на самом деле он такое свойство ждёт, то вам следует репортить этот баг автору компонента (предварительно обновившись до последней версии).declare module 'путь до типов компонента Swiper' {
interface SwiperProps {
spaceBetween: number;
}
}
<Row justify="space-around">
<Col flex="none">
...
</Col>
<Col flex="none">
...
</Col>
</Row>
<Row>
<Col span={12}>
<Row justify="center">
<Col flex="none">
...
</Col>
</Row>
</Col>
<Col span={12}>
<Row justify="center">
<Col flex="none">
...
</Col>
</Row>
</Col>
</Row>
const ThemeProvider: FC = ...;
ThemeProvider
имеет тип FC
, и пофиг что ты там дальше пишешь. Тип FC
по умолчанию не имеет children
.const ThemeProvider: FC<{children: ...}> = ...;
const ThemeProvider = ({ children }: ...) => ...;
props
, children
это поле props
, а не верхний аргумент.const ThemeProvider: FC<PropsWithChildren> = ...
PropsWithChildren
- тип помощник, добавляющий children
к объекту, например PropsWithChildren<{
prop2: string;
prop3: number
}>
но без дженерика просто отдаёт тип вида {
children?: ReactNode | undefined;
}
dangerouslySetInnerHTML
то предварительно её почистить можно так:function removeStyles(html) {
const container = document.createElement('div');
container.innerHTML = html;
container.querySelectorAll('style').forEach(
style => style.remove()
);
return container.innerHTML;
}
MutationObserver
или банальный setTimeout
. Однако в таком случае стили могут успеть отрисоваться до удаления, из-за чего может происходить мерцание.document.createElement
, отфильтровая ненужный style
. Но всё это уже требует понимания.:) _next
там где должен быть build
. Возможно одна из переменных окружения у вас кривая, или .env
файл. Если сходу не находится откуда взялся _next
- можно минимально оформатировать в ide уже собранные файлы и поискать в них это _next
, окружающий код скорее всего о чём-нить скажет вам./_next/static/chunks/
- это путь по умолчанию, если нужен иной - следует задать assetPrefix
._next
, а вы её переименовали? docx
явно не входит в стандартный набор форматов для front-end тебе потребуется установить и настроить специальный loader\плагин\asset в зависимости от системы сборки.fetch
.React.cteateElement(Component, ...)
вместо <Component ...>
. Про 60% библиотек и вспомогательных утилит тоже можно будет забыть, с ещё 20% придётся хорошенько повозиться чтоб запустить.RegisterService
?<RegisterService ...>
или React.createElement(RegisterService, ...)
. use
- useRegisterService
(отсутствие префикса не приведёт к ошибке, но это стандарт).