Автоматическое выделение чекбокса "Все" при нажатии на все другие чекбоксы v.2
Вот весь мой код, связанный с этой проблемой.
FilterBox.jsx
import React from 'react';
import classes from './filter-box.module.scss';
const FilterBox = ( props ) => {
const { filterData, checkAll } = props
const elements = filterData.map((el) => {
const { label, id, isChecked } = el
return (
<li key={id} className={classes['filter-item']}>
<label className={classes.filter__label}>
<input onChange={() => checkAll(id)} checked={isChecked} className={classes.filter__input} type="checkbox" />
<span className={classes.filter__check}> </span>
{label}
</label>
</li>
)
})
return (
<section className={classes['filter-box']}>
<h2 className={classes['filter-title']}>Количество пересадок</h2>
<ul className={classes['filter-list']}>
{elements}
</ul>
</section>
)
}
export default FilterBox;
reducer.js
const initialState = [
{label: "Все", id:1, isChecked: false},
{label: "Без пересадок", id:2, isChecked: false},
{label: "1 пересадка", id:3, isChecked: false},
{label: "2 пересадки", id:4, isChecked: false},
{label: "3 пересадки", id:5, isChecked: false},
]
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'CHECKED':
if (action.id === 1) {
if (state[0].isChecked === false) {
return state.map(el => ({...el, isChecked: true}))
} else {
return state.map(el => ({...el, isChecked: false}))
}
}
if (state[0].isChecked === false) {
const index = state.findIndex((el) => el.id === action.id)
const oldItem = state[index]
const newItem = {...oldItem, isChecked: !oldItem.isChecked }
return [...state.slice(0, index), newItem, ...state.slice(index + 1)]
} else {
const index = state.findIndex((el) => el.id === action.id)
const oldItem = state[index]
const allOldItem = state[0]
const allNewItem = {...allOldItem, isChecked: false}
const newItem = {...oldItem, isChecked: !oldItem.isChecked }
return [allNewItem, ...state.slice(1, index), newItem, ...state.slice(index + 1)]
}
default:
return state
}
}
export default reducer
index.js
import React from "react"
import ReactDOM from "react-dom"
import FilterBox from "./filter-box";
import {createStore, bindActionCreators} from "redux";
import reducer from "./reducer";
import * as actions from "./actions";
const store = createStore(reducer)
const { dispatch } = store
const { checked } =
bindActionCreators(actions, dispatch)
const update = () => {
ReactDOM.render(<FilterBox
filterData={store.getState()}
checkAll={checked}/>, document.getElementById("root"))
}
update()
store.subscribe(update)
И вот по всей этой информации мне нужно сделать так, чтобы первый чекбокс отмечался, когда все уже отмечены. Пробовал и через state.filter, и counter +- 1
Ответы (1 шт):
Автор решения: Konstantin Modin
→ Ссылка
Ок повторный ответ: из state я удалил объект "Все", будем рендерить его отдельно. FilterBox я подключил к Редакс так как это происходит на реальных проектах.
Имеем: App.js, reducer, initial state:
import React from "react";
import FilterBox from "./FilterBox";
import { createStore } from "redux";
import { Provider } from "react-redux";
const initialState = [
{ label: "Без пересадок", id: "2", isChecked: false },
{ label: "1 пересадка", id: "3", isChecked: false },
{ label: "2 пересадки", id: "4", isChecked: false },
{ label: "3 пересадки", id: "5", isChecked: false },
];
const reducer = (state = initialState, { type, payload }) => {
switch (type) {
case "CHECKED":
return state.map((item) =>
item.id === payload.id ? { ...item, isChecked: !item.isChecked } : item
);
case "CHECK_ALL":
return state.map((item) => ({ ...item, isChecked: payload.checked }));
default:
return state;
}
};
const store = createStore(reducer);
const App = () => {
return (
<Provider store={store}>
<FilterBox />
</Provider>
);
};
export default App;
FilterBox.js, actions:
import React from "react";
import { connect } from "react-redux";
const toggleCheckbox = (e) => ({
type: "CHECKED",
payload: {
id: e.target.id,
},
});
const toggleCheckAll = (e) => ({
type: "CHECK_ALL",
payload: {
checked: e.target.checked,
},
});
const FilterBox = ({ state, toggleCheckbox, toggleCheckAll }) => {
const renderInput = (label, id, isChecked, handler) => {
return (
<li key={id} className="filter-item">
<label className={"classes.filter__label"}>
<input
id={id}
onChange={(e) => handler(e)}
checked={isChecked}
className={"classes.filter__input"}
type="checkbox"
/>
<span className={"classes.filter__check"}> </span>
{label}
</label>
</li>
);
};
const renderElements = () => {
return state.map(({ label, id, isChecked }) =>
renderInput(label, id, isChecked, toggleCheckbox)
);
};
const areAllChecked = state.every((item) => item.isChecked);
return (
<section className={"filter-box"}>
<h2 className={"filter-title"}>Количество пересадок</h2>
<ul className={"filter-list"}>
{renderInput("Все", "1", areAllChecked, toggleCheckAll)}
{renderElements()}
</ul>
</section>
);
};
const mapStateToProps = (state) => ({ state });
export default connect(mapStateToProps, { toggleCheckbox, toggleCheckAll })(
FilterBox
);