Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save evgeniyworkbel/7c7267070c4a29fc91545f0dadbb212b to your computer and use it in GitHub Desktop.
Save evgeniyworkbel/7c7267070c4a29fc91545f0dadbb212b to your computer and use it in GitHub Desktop.
Курс "JS: React Hooks"
// @ts-check
/* eslint no-param-reassign: ["error", { "props": false }] */
import React from 'react';
import { useImmer } from 'use-immer';
import cn from 'classnames';
// BEGIN (write your solution here)
const Button = (props) => {
const { id, active, setActive } = props;
const [clickesCount, setCount] = useImmer(0);
const classes = cn('btn', `btn-${id === active ? 'success' : 'primary'}`, 'm-1');
const handleClick = (clickedId) => (ev) => {
ev.preventDefault();
setCount(clickesCount + 1);
setActive(clickedId);
};
return (
<button className={classes} type="button" onClick={handleClick(id)}>{clickesCount}</button>
);
};
const Buttons = (props) => {
const { count } = props;
const buttonsCount = count ?? 3;
const [activeButtonId, setActiveButtonId] = useImmer(null);
const ids = [];
for (let i = 0; i < buttonsCount; i += 1) {
ids.push(i);
}
return (
<>
{ids.map((id) => (
<Button
key={id}
id={id}
active={activeButtonId}
setActive={setActiveButtonId}
/>
))}
</>
);
};
export default Buttons;
// END
// @ts-check
/* eslint no-param-reassign: ["error", { "props": false }] */
import React from 'react';
import { useImmer } from 'use-immer';
import cn from 'classnames';
// BEGIN
const renderButton = (index, count, activeIndex, handleClick) => {
const className = cn('btn m-1', {
'btn-primary': activeIndex !== index,
'btn-success': activeIndex === index,
});
return (
<button
key={index}
type="button"
className={className}
onClick={handleClick}
>
{count}
</button>
);
};
const Buttons = ({ count = 3 }) => {
const initButtonsState = {
active: null,
counts: Array(count).fill(0),
};
const [buttonsState, updateButtonsState] = useImmer(initButtonsState);
const generateHandler = (index) => () => {
updateButtonsState((state) => {
state.active = index;
state.counts[index] += 1;
});
};
const { active, counts } = buttonsState;
return counts.map((buttonCount, index) => (
renderButton(index, buttonCount, active, generateHandler(index))
));
};
export default Buttons;
// END
Buttons.jsx
Реализуйте и экспортируйте по умолчанию компонент <Buttons />, который отрисовывает кнопки со значением счетчика.
В компоненте необходимо реализовать следующее поведение:
Текущее значение счетчика каждой кнопки — это строка внутри тега button.
Клик по кнопке должен увеличивать значение счетчика на единицу, не затрагивая при этом другие счетчики.
Компонент должен принимать пропс count, который определяет количество кнопок. Значение по умолчанию: 3.
Для оформления внешнего вида кнопок используйте библиотеку bootstrap (подключена к испытанию).
Последняя нажатая кнопка меняет цвет (с помощью класса). Классы в примерах ниже.
Примеры
Кнопки с нулевым значением счетчика:
<button class="btn btn-primary m-1" type="button">0</button>
<button class="btn btn-primary m-1" type="button">0</button>
<button class="btn btn-primary m-1" type="button">0</button>
Кнопки на которые нажимали. Последняя была вторая (btn-primary => btn-success):
<button class="btn btn-primary m-1" type="button">3</button>
<button class="btn btn-success m-1" type="button">1</button>
<button class="btn btn-primary m-1" type="button">2</button>
Подсказки
Решите эту задачу, используя функциональные компоненты и хуки
Используйте хук useImmer для управления состоянием https://github.com/immerjs/use-immer
Документация по хукам на русском языке: https://ru.reactjs.org/docs/hooks-intro.html
Статья "Как Immer покоряет React": https://ru.hexlet.io/blog/posts/kak-immer-pokoryaet-react
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment