Автоматическое выделение чекбокса "Все" при нажатии на все другие чекбоксы
Необходимо с помощью react-redux реализовать данный функционал
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
}
}
Cам инпут "Все" имеет id=1
Ответы (2 шт):
Автор решения: Konstantin Modin
→ Ссылка
Можно сделать например так: Рендерим все чекбоксы, и в конце рендерим чекбокс "отметить все", который отмечается если все чекбоксы отмечены. Дополнительно создаём action toggleCheckAll который будет отмечать или убирать галочки со всех чекбоксов, в зависимости от значения чекбокса checkAll.
App.js, reducer:
import React from "react";
import { createStore } from "redux";
import { Provider } from "react-redux";
import CheckBoxes from "./Checkboxes";
const initialState = [
{ id: "1", name: "name1", checked: false },
{ id: "2", name: "name2", checked: false },
{ id: "3", name: "name3", checked: true },
{ id: "4", name: "name4", checked: false },
];
const reducer = (state = initialState, { type, payload }) => {
switch (type) {
case "CHECKED":
return state.map((item) =>
item.id === payload.id ? { ...item, checked: !item.checked } : item
);
case "CHECK_ALL":
return state.map((item) => ({ ...item, checked: payload.checked }));
default:
return state;
}
};
const store = createStore(reducer);
const App = () => {
return (
<Provider store={store}>
<CheckBoxes />
</Provider>
);
};
export default App;
Checkboxes.js, actions:
import React from "react";
import { connect } from "react-redux";
const toggleCheckbox = (id) => ({
type: "CHECKED",
payload: {
id,
},
});
const toggleCheckAll = (checked) => ({
type: "CHECK_ALL",
payload: {
checked,
},
});
const Checkboxes = ({ state, toggleCheckbox, toggleCheckAll }) => {
return (
<div>
<h2>Checkboxes:</h2>
{state &&
state.map(({ id, name, checked }) => (
<div key={id}>
<label htmlFor={name}>{name}</label>
<input
name={name}
type="checkbox"
checked={checked}
onClick={() => toggleCheckbox(id)}
/>
</div>
))}
<label htmlFor="checkAll">Check All</label>
<input
name="checkAll"
type="checkbox"
checked={state.every((item) => item.checked)}
onClick={({ target: { checked } }) => toggleCheckAll(checked)}
/>
</div>
);
};
const mapStateToProps = (state) => ({ state });
export default connect(mapStateToProps, { toggleCheckbox, toggleCheckAll })(
Checkboxes
);
Автор решения: user431203
→ Ссылка
Пожалуй, скину ещё немного кода и информации
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