Update all react children components

120 Views Asked by At

I have a code like this:

<Editor source="/api/customer" onCreate={this.debugChange} onDelete={this.debugChange} onUpdate={this.debugChange}>
    <Group title="Address">
        <Column id="id" label="ID" default={0} readonly />
        <Column id="name" label="name" default="" />
        <Column id="address" label="Address" default="" />
        <Column id="country" label="Country" default={currentCountry} readonly source="/api/country" idfield="id" captionField="name" />
    </Group>
    <Group title="Payment">
        <Column id="tax" label="TaxType" default={0} source="/api/taxtype" idfield="id" captionField="name" />
        <Column id="bank" label="Bank" default="" source="/api/banks" idfield="id" captionField="bank"/>
        <Column id="account" label="Account Number" default="" />
    </Group>
</Editor>

Editor has a render() function like this:

    let components = React.Children.map(this.props.children, (child) => {
        return <Column {...child.props} default={row[child.props.id]} onChange={this.onChange.bind(this)} />
    })

    return <div className="hx-editor">
        <div className="hx-editor-list">
            <List id={this.props.id + "-list"} source={this.props.source}
                singleShow captionField={this.caption.bind(this)}
                groupfn={this.props.group} onSelect={this.onSelect.bind(this)} />
        </div>
        <form name={"hx-form-" + this.props.id} className="hx-form">
            {components}
            {buttons}
        </form>
    </div >

I have the function like this at <List>'s onSelect

private onSelect(id: string, data: T) {
    this.setState({
        currentRow: data,
        modifiedRow: data
    })
}

<Editor> will show a list from /api/customer with <List>, and send the selected values to onSelect props, which in turn update all <Column> children. The data corresponds with column's id, such as:

data = [{
    id: 0,
    name: 'My Customer',
    address: 'This is Address',
    country: 'US',
    tax: '010',
    bank: 'HSBC',
    account:: '89238882839304'
}, ... ]

This method that I put here, only works with children directly under <Editor>, but not under <Group>.

My question is, how can I do deep update of all values of <Column> as <Editor>'s children when a user clicked on a value in <List>. I mean, perform <Column> search through all children, and update all values, no matter where they are, as long as within <Editor> tag.

Any help is appreciated. Thank you

2

There are 2 best solutions below

0
On BEST ANSWER

Ok... This will break Typescript, I don't know how to type it in Typescript properly, but this one works.

private deepColumn(children: React.ReactNode) => any) {
    return React.Children.map(children, child => {
        if (child.props.children) {
            child = React.cloneElement(child, {
                children: this.deepColumn(child.props.children)
            })
        }
        if (child.type.name == "Column") {
            return <Column {...child.props} default={this.default} onChange={this.onChange.bind(this)} />
        } else return child;
    })
}
1
On

<Group /> as intermediate 'layer' will 'block change propagation` - this component is not 'consuming' any prop and is therefore not change aware.

You can/need:

  • change structure;
  • pass prop that will be changed (and will force updates in children);
  • use redux;
  • use context API.