В настоящее время я создаю компонент MultiCheckbox, например:
Checkbox.tsx
import './Checkbox.scss';
import React, {ChangeEvent, Component,} from 'react';
/*
* The properties of Checkbox
*/
interface ICheckboxProps<TYPE> {
id: string;
name: string;
value: TYPE;
checked?: boolean;
//if a cross should be used instead of a hook
cross?: boolean;
disabled?: boolean;
//should show a label on the right side of the checkbox
showLabel?: boolean;
//get the string for the value of the checkbox
labelFunc?: (value: TYPE) => string;
// an onChange function which gets called with the state.checked argument
onChange?: (checkbox: ICheckboxState<TYPE>) => void;
}
interface ICheckboxState<TYPE> {
// checked state of the checkbox
checked: boolean;
value: TYPE;
}
class CheckboxComponent<TYPE> extends Component<ICheckboxProps<TYPE>, ICheckboxState<TYPE>> {
constructor(props: ICheckboxProps<TYPE>) {
super(props);
console.log(props);
// set the initial state
this.state = {
checked: props.checked == null ? false : props.checked,
value: props.value,
};
console.log(props);
}
/*
* Render the component as ReactElement
*/
public render(): JSX.Element {
console.log('Checkbox render: ');
console.log(this.state);
return (
<div className={'checkbox'}>
<input
id={this.props.id}
type={'checkbox'}
name={this.props.name}
className={this.props.cross === true ? 'checkbox-cross' : 'checkbox-hook'}
onChange={this.onInputElementChangeEvent}
checked={this.state.checked}
disabled={this.props.disabled}
/>
{this.props.showLabel === true ? (
<label
className="checkbox-label"
htmlFor={this.props.id}>
{typeof this.props.labelFunc === 'function' ?
this.props.labelFunc(this.state.value) : String(this.state.value)}
</label>
) : null}
</div>
);
}
private onInputElementChangeEvent = (e: ChangeEvent<HTMLInputElement>): void => {
this.onChange(e.target.checked);
}
private onChange(checked: boolean): void {
// set the new state when the "onChange" event of the checkbox happens
this.setState({
checked: checked,
value: this.state.value,
}, () => {
// if there is an onChange function supscribed to the event handler than execute it with the current "checked" as
if (typeof this.props.onChange === 'function') {
this.props.onChange(this.state);
}
});
}
public isChecked(): boolean {
return this.state.checked;
}
//return only the value if it's checked
public getValue(): TYPE {
return this.state.value;
}
}
export const Checkbox = (CheckboxComponent);
и
MultiCheckbox.tsx
import './MultiCheckbox.scss';
import React, {Component,} from 'react';
import {Checkbox} from "../Checkbox";
/*
* The properties of Checkbox
*/
interface IMultiCheckboxProps<TYPE> {
id: string;
values: TYPE[];
idFunc: (value: TYPE) => any;
//if a cross should be used instead of a hook
cross?: boolean;
initialChecked?: boolean;
disabled?: boolean;
//get the string for the value of the checkbox
labelFunc: (value: TYPE) => string;
// an onChange function which gets called with the state.checked argument
onChange?: (selected: TYPE[]) => void;
//all checkbox
allButton?: boolean;
//empty checkbox value
emptyButton?: boolean;
//label for empty checkbox
emptyLabel?: string;
}
interface IMultiCheckboxState<TYPE> {
values: SelectedValue<TYPE>[];
all: boolean;
empty: boolean;
}
interface SelectedValue<TYPE> {
id: any;
value: TYPE;
selected: boolean;
}
class MultiCheckboxComponent<TYPE> extends Component<IMultiCheckboxProps<TYPE>, IMultiCheckboxState<TYPE>> {
constructor(props: IMultiCheckboxProps<TYPE>) {
super(props);
// set the initial state
this.state = {
values: props.values.map(value => {
return {
id: props.idFunc(value),
value: value,
selected: props.initialChecked == null ? false : this.props.initialChecked
};
}),
all: props.initialChecked == null ? false : this.props.initialChecked,
empty: false
};
}
/*
* Render the component as ReactElement
*/
public render(): JSX.Element {
console.log('render')
console.log(this.state);
const id = 'multicheckbox-' + this.props.id;
const subId = id + '-checkbox-';
var checkboxes = this.state.values.map(value =>
<Checkbox
key={subId + value.id}
id={subId + value.id}
name={this.props.labelFunc(value.value)}
checked={value.selected}
showLabel={true}
value={value.value}
labelFunc={this.props.labelFunc}
cross={this.props.cross}
disabled={this.props.disabled}
onChange={(state) => this.onCheckboxChanged(state.checked, state.value)}
/>
);
if (this.props.allButton) {
checkboxes = checkboxes.concat(
<Checkbox
key={subId + 'all'}
id={subId + 'all'}
name={'Alle'}
value={'Alle'}
showLabel={true}
labelFunc={(value) => value}
cross={this.props.cross}
disabled={this.props.disabled}
checked={this.state.all}
onChange={(state) =>
this.setAllChecked(state.checked)
}
/>
);
}
if (this.props.emptyButton) {
}
console.log(checkboxes);
return (
<div
id={id}
key={id}
>{checkboxes}</div>
);
}
private onCheckboxChanged(checked: boolean, value: TYPE): void {
alert(value.toString() + ' is checked: ' + checked);
//TODO set boolean true/false on this.state.values -> checked!
}
private setAllChecked(checked: boolean): void {
console.log(checked);
console.log(this.state);
this.setState({
values: this.state.values.map(val => {
return {
id: val.id,
value: val.value,
selected: checked
};
}),
all: checked,
empty: this.state.empty
}, this.onSelectedChanged);
}
private onSelectedChanged(): void {
if (this.props.onChange) {
this.props.onChange(this.state.values.map(value => {
return value.value
}));
}
}
}
export const MultiCheckbox = (MultiCheckboxComponent);
И моя главная проблема заключается в том, что всякий раз, когда я нажимаю All-Checkbox, другие записи не обновляются... Состояние изменяется в MultiCheckboxComponent, но конструктор не вызывается в Checkbox, поэтому его состояние не обновляется и не отображается правильно . Я новичок в React и хочу создать компонент без избыточного хранилища, который можно использовать в разных формах (локальное хранилище) и заполнять его значения/состояния вверх до более конкретного компонента, который хранит его в избыточном.
Нравиться:
FooComponent (list of Foo) -> MultiCheckboxComponent -> multiple Checkboxes
FeeComponent (list of Fee) -> MultiCheckboxComponent -> multiple Checkboxes
LuuComponent (stuff) -> single Checkbox
Но всякий раз, когда я вызываю setState() для MultiCheckboxComponent, происходит рендеринг, и рендеринг также происходит для CheckboxComponent, но реквизиты не используются (конструктор не вызывается). Как я могу установить состояние для ребенка от родителя?