简体   繁体   English

使用复选框反应嵌套组件

[英]React nested components with checkboxes

I have a website that contains more than a dozen components. 我有一个网站,其中包含十几个组件。

Each parent component contains about 5 other components. 每个父组件包含大约5个其他组件。 Each 5 components contains a form. 每个5个组件都包含一个表单。
Parent components has 3 checkboxes. 父组件具有3个复选框。

1: Expand all components in that offer (expand all), 1:展开该优惠中的所有组件(全部展开),
2: assign everything in that component (assign all), 2:分配该组件中的所有内容(全部分配),
3: Expand the component (expand product). 3:扩展组件(扩展产品)。

Each child component has two checkboxes. 每个子组件都有两个复选框。

1: Expand the component (also expand product), 1:展开组件(也展开产品),
2: assign everything from the component (also assign all). 2:分配组件中的所有内容(也分配所有内容)。

All of these options works on a state change. 所有这些选项均适用于状态更改。 They all work correctly. 它们都正常工作。 The problem is that when I click parent checkbox, I can not deselect the child's single component. 问题是,当我单击“父”复选框时,无法取消选择子级的单个组件。 So I can not uncheck the checkbox inside child's component (child's expand product or child's assign all) 因此,我无法取消选中子级组件内的复选框(子级扩展产品或子级全部分配)

closed components 封闭组件
expand product on parent 在父级上扩展产品
expand product in parent, expand product in child 在父级中扩展产品,在子级中扩展产品
expand all in parent,triggers expand product in parent and it triggers expand product in childs component 在父级中展开全部,触发在父级中展开产品,并触发在子级组件中展开产品

here's first file that renders parent component : 这是渲染父组件的第一个文件:

 class Offer extends React.Component {
 constructor(props){
    super(props);

    this.state = {
        checkedItems: new Map()
    };

    this.handleChange = this.handleChange.bind(this);
}

handleChange(e) {
    const item = e.target.name;
    const isChecked = e.target.checked;

    this.setState(prevState => ({
        checkedItems: prevState.checkedItems.set(item, isChecked)
    }));
}

render(){
    const { data, country_offer, country_offer_tab, countries, } = this.props;

    return (
        <div className="offer-wrapper">
            <div className={"offer-header " + data[2] }>
                <div>
                    <div className="custom_checkbox">
                        <div className="custom_checkbox">
                            <input
                                type={"checkbox"}
                                name={`${data[2]}_expand_all`}
                                className="expand_all"
                                checked={this.state.checkedItems.get(`${data[2]}_expand_all`) || false}
                                onChange={this.handleChange}
                                id={`${data[2]}_expand_all`}
                            />
                            <label htmlFor={`${data[2]}_expand_all`}>Expand all</label>
                        </div>
                        <div className="custom_checkbox">
                            <input
                                type={"checkbox"}
                                name={`${data[2]}_assign_all`}
                                className="assign_all"
                                checked={this.state.checkedItems.get(`${data[2]}_assign_all`) || false}
                                onChange={this.handleChange}
                                id={`${data[2]}_assign_all`}
                            />
                            <label htmlFor={`${data[2]}_assign_all`}>Assign all products</label>
                        </div>
                        <div className="custom_checkbox">
                            <input
                                type={"checkbox"}
                                name={`${data[2]}_expand_product`}
                                className="expand_product"
                                checked={( this.state.checkedItems.get(`${data[2]}_expand_product`) || this.state.checkedItems.get(`${data[2]}_expand_all`) ) || false}
                                onChange={this.handleChange}
                                id={`${data[2]}_expand_product`}
                            />
                            <label htmlFor={`${data[2]}_expand_product`}>Expand product</label>
                        </div>
                    </div>
                </div>
            </div>

            {
                (this.state.checkedItems.get(`${data[2]}_expand_all`) || this.state.checkedItems.get(`${data[2]}`+'_expand_product'))  &&
                    <CountryOffer
                        country_offer_tab={country_offer_tab}
                        countries={countries}
                        data={data}
                        expand_all={this.state.checkedItems.get(`${data[2]}_expand_all`)}
                        expand_product={this.state.checkedItems.get(`${data[2]}_expand_product`)}
                        assign_all={this.state.checkedItems.get(`${data[2]}_assign_all`)}
                    />
            }
        </div>
    )
}
}

export default Offer;

and here is child component 这是子组件

class CountryOffer extends React.Component{
constructor(props){
    super(props);

    this.state = {
        checkedItems: new Map(),
    };

    this.handleChange = this.handleChange.bind(this);
}

handleChange(e) {
    if (!this.props.expand_all){
        const item = e.target.name;
        const isChecked = e.target.checked;

        this.setState(prevState => ({
            checkedItems: prevState.checkedItems.set(item, isChecked)
        }));
    } else {
        console.log('cant uncheck/check this')
    }
}

render(){
    const { country_offer_tab, countries, data, expand_all, expand_product, assign_all} = this.props;
    return (
        <div className={"offer-details " + data[2]}>
            {country_offer_tab[data[2]].map((country, k) => {
                return (
                    <div key={k}>
                        <div className="offer-country-header" >
                            <div>
                                <span className={"iti-flag "+(countries[k].symbol).toLowerCase()}/>
                                <span>{countries[k].name}</span>
                            </div>
                            <div className='custom_checkbox'>
                                <input
                                    checked={assign_all ? assign_all : (this.state.checkedItems.get(`intersections_for ${data[2]}|${countries[k].id}`) || false)} onChange={this.handleChange}
                                    type="checkbox"
                                    name={"intersections_for "+ data[2] + '|' + countries[k].id}
                                    id={"intersections_for "+ data[2] + '|' + countries[k].id}/>
                                <label className="intersections_group_label" htmlFor={"intersections_for "+ data[2] + '|' + countries[k].id}>Check/uncheck all</label>
                            </div>
                            <div className='custom_checkbox'>
                                <input
                                    checked={expand_all ? expand_all : (this.state.checkedItems.get(`expand_geo ${data[2]}|${countries[k].id}`) || false)} onChange={this.handleChange}
                                    type="checkbox"
                                    name={"expand_geo " + data[2] + '|' + countries[k].id}
                                    id={"expand_geo " + data[2] + '|' + countries[k].id}/>
                                <label htmlFor={"expand_geo "+ data[2] + '|' + countries[k].id}>Expand GEO</label>
                            </div>
                        </div>

                        {
                            (expand_all || this.state.checkedItems.get(`expand_geo ${data[2]}|${countries[k].id}`)) &&
                                <CountryOfferIntersections
                                    country_offer_tab={country_offer_tab}
                                    offer_id={data[2]}
                                    country_id={countries[k].id}
                                    check_all={this.state.checkedItems.get(`intersections_for ${data[2]}|${countries[k].id}`)}
                                    assign_all={assign_all}
                                    expand_product={expand_product}
                                />
                        }
                    </div>
                )
            })}
        </div>
    )}
}

 export default CountryOffer;

I will be grateful for any help 我将不胜感激

If true , the assign_all prop overrides any local state in CountryOffer 如果为true ,则assign_all CountryOffer会覆盖CountryOffer任何本地状态

checked={assign_all ? assign_all : ...

This is a problem with not having a single source of truth. 这是没有单一真相来源的问题。 I would refactor your code so that CountryOffer is a stateless component, and keep all state in the parent Offer component. 我将重构您的代码,以使CountryOffer是无状态组件,并将所有状态保留在父Offer组件中。

Alternatively lifting management of shared state out of the components altogether. 或者,将共享状态的管理完全从组件中删除。 (For example with react context , redux, rxjs) (例如与react context ,redux,rxjs一起使用)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM