const ClickableArea = ({ component: Component = 'div', to, children, ...props }) => {
const history = useHistory();
const control = useRef(null);
const handleClick = useCallback((event) => {
if (event.target === control.current) {
history.push(to);
}
}, [history, control, to]);
return (
<Component ref={control} onClick={handleClick} tabIndex={-1} {...props}>
{children}
</Component>
);
};
<ClickableArea
className={classes.tweet}
component={Paper}
variant="outlined"
to={`/home/tweet/${_id}`}
>...</ClickableArea>
::after
на ссылке растянуть её на весь контейнер. При помощи display: grid/flex
на родителе можно будет поправить всем остальным элементам z-index
. React.StrictMode
отсутствует.App
подписываетесь на изменения store
и обновляете состояние им.src/style.css
, а надо бы для каждого компонента их разделять. Я бы разбивал на модули..jsx
используйте только для компонентов. У Вас есть файлы с логикой, которые имеют такое расширение.sirch-panel.jsx
(а еще лучше бы SearchPanel.jsx
) лучше хранить состоянием только значение поля для новой сущности.store.dispatch
. Диспатчинг событий можно перенести в тот же connect (можно даже bindActionCreators использовать).switch
. Для удаления можете воспользоваться методом массива .filter
. Для пометки important можете воспользоваться методом массива .map
. И вообще его вынести в отдельную директорию, т. к. он не является компонентом (как и action creators).className={important ? "important list-item" : "list-item"}
можете воспользоваться classnames или clsx.id: idCounter
можно будет заменить на Date.now()
. export const ModalBlock: React.FC<ModalBlockProps> = ({
title,
onClose,
isOpen = false,
children,
}: ModalBlockProps): React.ReactElement | null => {
const [closing, setClosing] = useState(false);
const handleClose = () => setClosing(true);
useEffect(() => {
if (isOpen) {
setClosing(false);
}
}, [isOpen]);
if (!isOpen) {
return null;
}
return (
<Dialog TransitionComponent={Transition} open={!closing && isOpen} onExited={onClose} aria-labelledby='form-dialog-title'>
<DialogTitle id='form-dialog-title'>
<IconButton onClick={handleClose} color='secondary' aria-label='close'>
<CloseIcon style={{ fontSize: 26 }} color='secondary' />
</IconButton>
{title}
</DialogTitle>
<DialogContent>{children}</DialogContent>
</Dialog>
);
};
const ThemedInput = withStyles((theme) => ({
root: {
"&:hover": {
"&$underline": {
"&::before": {
borderColor: theme.palette.primary.dark
}
}
}
},
input: {
fontWeight: 700,
color: theme.palette.primary.main
},
underline: {
"&::before": {
borderColor: theme.palette.primary.main
}
}
}))(Input);
const ThemedSelect = withStyles((theme) => ({
select: {
"&:hover": {
"& ~ $icon": {
color: theme.palette.primary.dark
}
}
},
icon: {}
}))(Select);
<ThemedSelect input={<ThemedInput />}></ThemedSelect>
useEffect(() => {
let intervalId = setInterval(async () => {
const response = await fetch('http://127.0.0.1:8000/api/timecalculate', {
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
credentials: 'include',
});
const content = await response.json();
const now = new Date();
console.log(content + now);
}, 10000)
return () => {
clearInterval(intervalId);
};
}, []);
useEffect
;deps
передаете пустой массив;const PageSize = () => {
const [pageSize, setPageSize] = useState([document.documentElement.scrollWidth, document.documentElement.scrollHeight]);
const updatePageSize = () => setPageSize([document.documentElement.scrollWidth, document.documentElement.scrollHeight]);
useEffect(() => {
window.addEventListener('resize', updatePageSize);
return () => {
window.removeEventListener('resize', updatePageSize);
};
}, []);
return (
<div>
<p>page width is {pageSize[0]}</p>
<p>page height is {pageSize[1]}</p>
</div>
);
};
mousemove
. Приложение работает, всё хорошо, но потом, по некоторой причине, происходит размонтирование и через некоторое время снова монтирование. В таком случае, если не удалить прослушку, будет уже 2 события, что и является утечкой памяти.