我当前正在创建一个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);
我的主要问题是,每当我单击“所有复选框”时,其他条目都不会更新... 在“ MultiCheckboxComponent”上更改了状态get,但在“ Checkbox”上未调用“构造函数”,因此其状态未更新并正确呈现。我是React的新手,我想创建一个没有“ redux-store”的组件,该组件可用于不同形式(本地存储),并将其值/状态向上填充到一个更特定的组件中,以将其存储在redux中。 >
赞:
FooComponent (list of Foo) -> MultiCheckboxComponent -> multiple Checkboxes
FeeComponent (list of Fee) -> MultiCheckboxComponent -> multiple Checkboxes
LuuComponent (stuff) -> single Checkbox
但是,每当我在MultiCheckboxComponent上调用“ setState()”时,都会发生“渲染”,并且也发生在CheckboxComponent上,但是不会使用“ props”(未调用“ Constructor”)。如何在“父母”的“孩子”上设置状态?
答案 0 :(得分:1)
我认为您遇到了麻烦,因为您正在考虑应如何以某种错误的方式对此类事物进行建模。
构造函数仅在创建组件时被调用一次。我认为复选框组件内部的状态不是必需的-毕竟-它们似乎在很大程度上复制了道具。
在编写React代码时-将您的props视为更改值,这些值将触发子组件中的更新。使用它们来影响组件的外观。
这是我要进行的一些更改:
这将为您提供以下内容:
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;
}
function CheckboxComponent<TYPE>(props: ICheckboxProps<TYPE>) {
console.log('Checkbox render: ');
// Destructure props - save writing out this.props.foo each time
const { name, id, cross, onChange, checked, disabled, showLabel } = this.props;
return (
<div className="checkbox">
<input
id={id}
type="checkbox"
name={name}
className={cross ? 'checkbox-cross' : 'checkbox-hook'}
onChange={(e) => onChange && onChange(e.target.checked)}
checked={checked}
disabled={disabled}
/>
{showLabel && (
<label className="checkbox-label" htmlFor={id}>
{labelFunc ? labelFunc(value) : value}?
</label>
)}
</div>
);
}
export const Checkbox = (CheckboxComponent);
如果您需要任何进一步的帮助,请告诉我!