[英]Rerender child when parent state is updated
I am currently creating a MultiCheckbox Component like:我目前正在创建一个 MultiCheckbox 组件,如:
Checkbox.tsx复选框.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);
and the和
MultiCheckbox.tsx 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);
And my main problem is that whenever I click on the "All-Checkbox" the other entries are not updated... The state get's changed on the "MultiCheckboxComponent", but the "constructor" is not called on the "Checkbox", so it's state is not updated and rerendered correctly.我的主要问题是,每当我点击“All-Checkbox”时,其他条目都不会更新......“MultiCheckboxComponent”上的状态发生了变化,但是“Checkbox”上没有调用“构造函数”,所以它的状态未正确更新和重新渲染。 I am new to React and I want to create a component without "redux-store" which can be used on different forms (local-store) and populates it's values/states upwards to a more specific component which stores it in redux.
我是 React 的新手,我想创建一个没有“redux-store”的组件,它可以在不同的形式(本地存储)上使用,并将它的值/状态向上填充到一个更具体的组件,将它存储在 redux 中。
Like:喜欢:
FooComponent (list of Foo) -> MultiCheckboxComponent -> multiple Checkboxes
FeeComponent (list of Fee) -> MultiCheckboxComponent -> multiple Checkboxes
LuuComponent (stuff) -> single Checkbox
But whenever I call "setState()" on the MultiCheckboxComponent the "render" happens, and render also happens on CheckboxComponent, but the "props" are not used ("Constructor" not called).但是每当我在 MultiCheckboxComponent 上调用“setState()”时,“render”就会发生,并且渲染也会在 CheckboxComponent 上发生,但是没有使用“props”(“Constructor”没有被调用)。 How can I set the state on the "Child" from the "Parent"?
如何从“父”设置“子”的状态?
I believe you're having trouble because you're thinking about how these sort of things should be modelled in react in slightly the wrong way.我相信您遇到了麻烦,因为您正在考虑如何以稍微错误的方式对此类事物进行建模以做出反应。
The constructor is only called once - when the component is created.构造函数只调用一次 - 在创建组件时。 I don't think the state inside your checkbox components is necessary - after all - they seem to be pretty much duplicating the props.
我不认为你的复选框组件内的状态是必要的——毕竟——它们似乎几乎是在复制道具。
When you write React code - think of your props as changing values that will trigger updates in your child components.当您编写 React 代码时 - 将您的 props 视为将触发子组件更新的更改值。 Use these to affect how the component looks.
使用这些来影响组件的外观。
Here's some changes I'd make:这是我要做的一些更改:
This leaves you with the following:这给您留下了以下内容:
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);
Let me know if you need any further help with this!如果您需要任何进一步的帮助,请告诉我!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.