Ранее на этой неделе я опубликовал статью об отзывчивых и пользовательских компонентах с Chakra-ui в Next.js.
Я хотел написать продолжение и сосредоточиться на отзывчивом макете, и компонент сетки Chakra-ui позволяет сделать это с легкостью и удовольствием.
Я сделал небольшую демонстрацию, отображающую некоторых друзей на небольшой карточке, похожей на профиль, основываясь на том, что я объяснил в своей предыдущей статье.
//pages/index.js
const Home = () => {
const mainRef = useRef();
const dimensions = useDimensions(mainRef, true);
const [size, setSize] = useState('');
useEffect(() => {
if (dimensions) {
let width = dimensions.borderBox.width;
switch (true) {
case width < 499:
setSize('base');
break;
case width >= 499 && width < 696:
setSize('sm');
break;
case width >= 696 && width < 945:
setSize('md');
break;
case width >= 945:
setSize('lg');
break;
}
}
}, [dimensions]);
return (
<>
<Nav />
<Box
w="100vw"
h="100vh"
display="flex"
justifyContent="center"
ref={mainRef}
alignItems="flex-start"
as="main"
>
<Layout>
<MyGrid />
<Box fontSize={{ base: '20px', sm: '24px' }} mt="30px">
<Text display="flex" justifyContent="center">
Width: {dimensions && dimensions.borderBox.width}px
</Text>
<Text display="flex" justifyContent="center">
Custom breakpoint size: {size}
</Text>
</Box>
</Layout>
</Box>
</>
);
};
export default Home;
Компонент index возвращает фрагмент React, содержащий простой пользовательский компонент Nav и компонент-контейнер Layout для размещения нашего компонента Grid.
//components/MyGrid.js
import profiles from '../profiles.json';
const MyGrid = () => {
return (
<>
<Grid
templateColumns={{ base: '1fr', lg: 'repeat(2, 1fr)' }}
h="100%"
gap="10px"
overflow="auto"
css={{
'&::-webkit-scrollbar': {
width: '4px',
},
'&::-webkit-scrollbar-track': {
width: '6px',
},
'&::-webkit-scrollbar-thumb': {
background: 'primary',
borderRadius: '24px',
},
}}
>
{profiles.map((profile) => (
<GridItem
key={profile.id}
h="150px"
bg="primary"
borderRadius="10"
color="white"
display="flex"
pl={{ base: '10px', sm: '25px', lg: '15px' }}
alignItems="center"
>
<Box display="flex" alignItems="center">
<ItemAvatar imageSrc={profile.imageSrc} name={profile.name} />
</Box>
<Details
name={profile.name}
title={profile.title}
link={profile.linkSrc}
/>
</GridItem>
))}
</Grid>
</>
);
};
export default MyGrid;
Компонент Grid импортирует json-файл из нашего корня, мы отображаем эти данные и для каждого объекта в этом массиве возвращаем элемент Grid из Chakra, с компонентом Avatar из Chakra и нашим собственным компонентом Details внутри.
//components/Details.js
import { Box, Text } from '@chakra-ui/react';
import Link from 'next/link';
const Details = ({ name, title, link }) => {
return (
<Box
display="flex"
flexDirection="column"
pl={{ base: '10px', sm: '25px', lg: '15px' }}
fontSize={{ base: '12px', sm: '14px', md: '16px', lg: '14px' }}
>
<Text fontSize="20px"> {name} </Text>
<Text as="i">{title}</Text>
<Text color="#03fcfc" as="i">
<Link href={link}>{link}</Link>
</Text>
</Box>
);
};
export default Details;
На протяжении всей этой статьи вы заметили {{base: 'someValue', sm: 'someValue', ...}}
синтаксис в некоторых реквизитах компонентов, и вы можете увидеть, как я объясняю его более подробно в моей другой статье, но если кратко, то он указывает реквизиту определенное значение, основанное на пользовательских точках останова, которые мы определили в теме.
//styles/ChakraTheme.js
import { extendTheme } from '@chakra-ui/react';
const theme = extendTheme({
colors: {
primary: '#201D29',
},
breakpoints: {
sm: '499px',
md: '696px',
lg: '945px',
},
});
export default theme;
Наконец, чтобы помочь нам визуализировать наши точки останова, мы можем использовать хук из Chakra, чтобы получить ширину нашего Box, который обертывает наш компонент Layout, и сохранить ее в состоянии, и она будет обновляться в useEffect каждый раз при изменении размера компонента.
import { useRef, useState, useEffect } from 'react';
import { Box, Text } from '@chakra-ui/react';
import MyGrid from '../components/MyGrid';
import Layout from '../components/Layout';
import Nav from '../components/Nav';
import { useDimensions } from '@chakra-ui/react';
const Home = () => {
const mainRef = useRef();
const dimensions = useDimensions(mainRef, true);
const [size, setSize] = useState('');
useEffect(() => {
if (dimensions) {
let width = dimensions.borderBox.width;
switch (true) {
case width < 499:
setSize('base');
break;
case width >= 499 && width < 696:
setSize('sm');
break;
case width >= 696 && width < 945:
setSize('md');
break;
case width >= 945:
setSize('lg');
break;
}
}
}, [dimensions]);
return (
<>
<Nav />
<Box
w="100vw"
h="100vh"
display="flex"
justifyContent="center"
ref={mainRef}
alignItems="flex-start"
as="main"
>
<Layout>
<MyGrid />
<Box fontSize={{ base: '20px', sm: '24px' }} mt="30px">
<Text display="flex" justifyContent="center">
Width: {dimensions && dimensions.borderBox.width}px
</Text>
<Text display="flex" justifyContent="center">
Custom breakpoint size: {size}
</Text>
</Box>
</Layout>
</Box>
</>
);
};
export default Home;
При начальной загрузке состояние размера является пустой строкой const [size, setSize] = useState('')
и будет обновляться в useEffect, после первого рендеринга на экран.
Каждый раз, когда объект dimensions из Chakra обновляется, он запускает функцию useEffect. Эта функция использует оператор switch, чтобы определить, на что обновить состояние размеров.
Вы можете посмотреть исходный код здесь
И следовать за мной здесь