передать состояние нажатия на кнопку в объект массива и запретить нажатие на кнопку из коллекции react
У меня есть коллекция кнопок, и я хочу, чтобы при нажатии на определенную кнопку не нажималась аналогичная кнопка в других коллекциях.
Например:
<div>
<button>A-1</button>
<button>A-2</button>
<button>A-3</button>
<button>B-1</button>
<button>B-2</button>
<button>B-3</button>
</div>
<div>
<button>A-1</button>
<button>A-2</button>
<button>A-3</button>
<button>B-1</button>
<button>B-2</button>
<button>B-3</button>
</div>
И когда я нажимаю на кнопку B-3, я хочу, чтобы все кнопки B-3, кроме текущей, были как disabled.
Например, я щелкаю на кнопке B-3, и все B-3 отключаются, кроме текущей.
На самом деле это легко сделать, но я хочу хранить состояние нажатой кнопки в хуке в ключе объекта массива. И передавать в хук состояние нажатых кнопок типа B-*:
const [Buttons, setButtons] = useState([{ ClickedButtons: [null, null] }]);
null #1 - `A-*` кнопки
null #2 - `B-*` кнопки
Немного не понимаю, как заносить состояние нажатой кнопки в этот хук, и отключать все аналогичные. Помогите, пожалуйста.
<ClickedButtons id={1} />
<ClickedButtons id={2} />
<ClickedButtons id={3} />
<ButtonShow clickFn={btnClick} id={1} buttons={buttons} />
<ButtonShow clickFn={btnClick} id={2} buttons={buttons} />
<ButtonShow clickFn={btnClick} id={3} buttons={buttons} />
Ответы (2 шт):
И когда я нажимаю на кнопку B-3, я хочу, чтобы все кнопки B-3, кроме текущей, были как disabled.
Предложу такой вариант...
const arr = [
['A-1', 'A-2', 'A-3', 'B-1', 'B-2', 'B-3'],
['A-1', 'A-2', 'A-3', 'B-1', 'B-2', 'B-3'],
]
//
function App() {
const [slct, setSlct] = React.useState({})
console.log(slct)
return <section>
{arr.map((a, i) => <Blk key={i} arr={a} line={i} set={setSlct} slct={slct} />)}
</section>
}
//
function Blk({arr, line, set, slct}) {
const act = e => {
const o = e.target
const ol = o.closest('.blk')
const i = +ol.dataset.line
const v = o.textContent
set(old => {
if (old[v] !== undefined) delete old[v]
else old[v] = i
return {...old}
})
}
return <div className="blk" data-line={line}>
{arr.map(v => <button className={cls(v)} onClick={act} key={v} disabled={dis(v)}>{v}</button>)}
</div>
//
function cls(v) {
if (slct[v] === line) return 'on'
return null
}
//
function dis(v) {
if (slct[v] === undefined) return false
if (slct[v] !== line) return true
return false
}
}
const domContainer = document.querySelector('#like_button_container');
const root = ReactDOM.createRoot(domContainer);
root.render(<App />);
.blk {
margin: 10px;
}
.on {
background-color: green;
}
<div id="like_button_container"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
Реализовать такое поведение можно, допустим, сохраняя в состояние кнопки ID "контейнера", где был произведен клик и при рендере проверять:
- Если клика нет
clickId === 0, кнопка активна - Если клик был, то проверяем, что клик был в текущем контейнере
- Если в текущем, кнопка активна иначе не активна
Создадим, к примеру, такую структуру для каждой кнопки:
{
name: "A-1", // Название кнопки
clickId: 0, // Где нажата
buttonId: 1, // ID кнопки
},
Создадим компонент, который будет отвечать за рендер кнопок и их состояние
const ButtonShow = ({ buttons, id, clickFn }) => {
return (
<>
{buttons.map((button) => (
<button
// По клику передаем Id кнопки и id контейнера
onClick={() => clickFn(button.buttonId, id)}
// Если заполнен клик и он не из этого контейнера, отключаем кнопку
disabled={button.clickId && button.clickId !== id}
>
{button.name}
</button>
))}
</>
);
};
В основном компоненте создаем состояние и функцию обработчик клика по кнопке
function App() {
const [buttons, setButtons] = useState([...buttonsInit]);
const btnClick = (btnId, rndId) => {
setButtons((prev) => {
return prev.map((btn) => {
// Если ID кнопки не совпало, возвращаем элемент как есть
if (btn.buttonId !== btnId) return btn;
// Если ID контейнера совпадает, отключаем клик
// Если нет, устанавливаем
btn.clickId = rndId === btn.clickId ? 0 : rndId;
return btn;
});
});
};
return (
<div className="App">
<hr />
<ButtonShow clickFn={btnClick} id={1} buttons={buttons} />
<br />
<ButtonShow clickFn={btnClick} id={2} buttons={buttons} />
<br />
<ButtonShow clickFn={btnClick} id={3} buttons={buttons} />
<br />
</div>
);
}
Полный код:
const buttonsInit = [
{
name: "A-1",
clickId: 0,
buttonId: 1,
},
{
name: "A-2",
clickId: 0,
buttonId: 2,
},
{
name: "B-1",
clickId: 0,
buttonId: 3,
},
{
name: "B-2",
clickId: 0,
buttonId: 4,
},
];
const ButtonShow = ({ buttons, id, clickFn }) => {
return (
<>
{buttons.map((button) => (
<button
onClick={() => clickFn(button.buttonId, id)}
disabled={button.clickId && button.clickId !== id}
>
{button.name}
</button>
))}
</>
);
};
function App() {
const [buttons, setButtons] = useState([...buttonsInit]);
const btnClick = (btnId, rndId) => {
setButtons((prev) => {
return prev.map((btn) => {
if (btn.buttonId !== btnId) return btn;
btn.clickId = rndId === btn.clickId ? 0 : rndId;
return btn;
});
});
};
return (
<div className="App">
<hr />
<ButtonShow clickFn={btnClick} id={1} buttons={buttons} />
<br />
<ButtonShow clickFn={btnClick} id={2} buttons={buttons} />
<br />
<ButtonShow clickFn={btnClick} id={3} buttons={buttons} />
<br />
</div>
);
}
Рабочий пример в песочнице