简体   繁体   English

动态更新复选框输入的 state

[英]Updating the state for checkboxes Inputs dynamically

I'm trying to generate a state property dynamically for an array of filters.我正在尝试为过滤器数组动态生成 state 属性。 These filters contain different checkboxes "names" and "isChecked" for each.这些过滤器分别包含不同的复选框“名称”和“isChecked”。 See below example:请参阅以下示例:

0: {name: "accompanying", isChecked: false}
1: {name: "bolting", isChecked: false}
2: {name: "carrying", isChecked: false}
3: {name: "coursing", isChecked: false}
4: {name: "defending", isChecked: false}
5: {name: "droving", isChecked: false}... 

Note: There are around 140 in total.注:总共约有 140 个。

To get to this list I'm filtering a list I'm fetching from a server thus, I can filter duplicates and map it correctly.为了获得此列表,我正在过滤从服务器获取的列表,因此,我可以正确过滤重复项和 map。 All of this happens in the render method.所有这些都发生在 render 方法中。

Also, see the initial state. The property I need to update is "filter":另外,请参阅初始 state。我需要更新的属性是“过滤器”:

    state = {
        dogFilter: '',
        formIsOpen: false,
        advancedFilterRequested: false,
        filters: [],
    };

Inside the render method, I'm calling a method from my class that is supposed to update the "filters" property from the state. See below:在渲染方法中,我从我的 class 调用一个方法,该方法应该更新 state 的“过滤器”属性。见下文:

updateFiltersHandler = (filters) => {
    this.setState({ filters: filters });
};
render() {
        let breedForFilters;
        let temperamentMainFilters;
        let temperamentAdvancedFilter;
         
        //data coming from the reducer  
        if (this.props.dogs) {
            const initialDogsBreedForFilter = this.props.dogs
                .map((dog) => dog.bred_for)
                .join(' , ')
                .split(' ')
                .filter((word) => {
                    return word.endsWith('ing');
                })
                .map((word) => word.toLowerCase())
                .filter((word) => word !== 'driving')
                .sort();

            const dogsBreedWithoutDuplicates = removeDublicates(
                initialDogsBreedForFilter
            );

            // filters data before allocating it to elements TEMPERAMENT

            const initialTemperamentFilter = this.props.dogs
                .map((dog) => dog.temperament)
                .join(' , ')
                .split(' ')
                .filter((word) => word.length > 3)
                .map((word) => word.replace(',', '').toLowerCase())
                .sort();

            // SPLITS MAIN AND ADVANCED FILTERS IN TEMPERAMENT

            const advancedTemperamentFilters = initialTemperamentFilter.filter(
                (word) =>
                    word !== 'stubborn' &&
                    word !== 'playful' &&
                    word !== 'active' &&
                    word !== 'friendly' &&
                    word !== 'intelligent' &&
                    word !== 'gentle' &&
                    word !== 'gay'
            );

            const mainTemperamentsFilters = initialTemperamentFilter.filter(
                (word) =>
                    word === 'stubborn' ||
                    word === 'playful' ||
                    word === 'active' ||
                    word === 'friendly' ||
                    word === 'intelligent' ||
                    word === 'gentle'
            );

            //REMOVES DUPLICATES FROM MAIN LIST USING A HELPER FUNCTION 

            const mainTemperamentsFiltersNoDuplicates = removeDublicates(
                mainTemperamentsFilters
            );

            const advancedTemperamentFiltersNoDuplicates = removeDublicates(
                advancedTemperamentFilters
            );

            // Sets state for Filters CheckBoxes: => here is where I need help! 

            const filterBreedFor = dogsBreedWithoutDuplicates;

            const filtersForIntialState = filterBreedFor
                .concat(
                    mainTemperamentsFiltersNoDuplicates,
                    advancedTemperamentFiltersNoDuplicates
                )
                .map((filter) => {
                    return { name: filter, isChecked: false };
                });

            this.updateFiltersHandler(filtersForIntialState); 

            //BUILDS RENDER ELEMENTS

            breedForFilters = filterBuilder(
                'breedForFilter',
                dogsBreedWithoutDuplicates,
                this.onChangeCheckboxHandler
            );

            temperamentMainFilters = filterBuilder(
                'temperament',
                mainTemperamentsFiltersNoDuplicates,
                this.onChangeCheckboxHandler
            );

            temperamentAdvancedFilter = filterBuilder(
                'temperament',
                advancedTemperamentFiltersNoDuplicates,
                this.onChangeCheckboxHandler
            );
        }

        // CLASSES

        let formClass = [styles.FormHolder];
        if (this.state.formIsOpen) {
            formClass = [styles.FormHolder, styles.ShowForm];
        }

        let advancedFilterClass = [styles.OptionsHolderAdvanced];

        if (this.state.advancedFilterRequested) {
            advancedFilterClass = [styles.OptionsHolderAdvanced, styles.Show];
        }
        return (
            <React.Fragment>
                <MainNavbar />
                <header className={styles.FindADogFiltersSection}>
                    <h2>find your perfect puppy</h2>
                    <SectionDivider />
                    <div className={styles.FidDogFiltersHolder}>
                        <div className={styles.FilterBtn} onClick={this.openFormHandler}>
                            filters
                        </div>
                    </div>
                    <form className={formClass.join(' ')}>
                        <header className={styles.FormHeader}>
                            <FontAwesomeIcon
                                icon={faTimes}
                                className={styles.CloseFilterSectionBtn}
                                onClick={this.closeFormHandler}
                            />
                            <h2> filters </h2>
                            <button
                                className={styles.ClearSearch}
                                onClick={(event) => {
                                    event.preventDefault();
                                    this.clearFiltersHandler();
                                }}
                            >
                                clear
                            </button>
                        </header>
                        <div className={styles.OptionsSection}>
                            <div className={styles.CategoriesHolder}>
                                <h3>breed for</h3>
                                <div className={styles.OptionsHolder}>{breedForFilters}</div>
                            </div>

                            <div className={styles.CategoriesHolder}>
                                <h3>temperament</h3>
                                <div className={styles.OptionsHolder}>
                                    {temperamentMainFilters}
                                </div>
                                <div className={styles.AdvanceFiltersBtnHolder}>
                                    <button
                                        onClick={(event) => {
                                            event.preventDefault();
                                            this.openandCloseAdvancedSearch();
                                        }}
                                    >
                                        advanced
                                    </button>
                                </div>
                                <div className={advancedFilterClass.join(' ')}>
                                    {temperamentAdvancedFilter}
                                </div>
                            </div>
                            <div className={styles.CategoriesHolder}>
                                <h3>Size</h3>
                                <div className={styles.OptionsHolder}>
                                    <div key="small">
                                        <input type="checkbox" name="breedFor" value="35" />
                                        <label>Small</label>
                                    </div>
                                    <div key="big">
                                        <input type="checkbox" name="breedFor" value="36" />
                                        <label>Big</label>
                                    </div>
                                </div>
                            </div>
                            <div className={styles.SearchBtnHolder}>
                                <button
                                    className={styles.SearchBtn}
                                    onClick={(event) => {
                                        event.preventDefault();
                                        this.searchRequestHandler();
                                        this.setState({ advancedFilterRequested: false });
                                    }}
                                >
                                    search
                                </button>
                            </div>
                        </div>
                    </form>
                </header>
                <FinderDisplayDogs data={this.props.dogs} />
                <MainFooter />
            </React.Fragment>
        );
    }

Im getting the following error我收到以下错误

Error: Maximum update depth exceeded.错误:超出最大更新深度。 This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate.当组件在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState 时,就会发生这种情况。 React limits the number of nested updates to prevent infinite loops. React 限制嵌套更新的数量以防止无限循环。

Is there a different way to update the state here.有没有不同的方法来更新 state 在这里。 I'm new to react so not sure what to do next.我是新手,所以不确定下一步该怎么做。 I tried using componentDidMounth but I get the same error.我尝试使用 componentDidMounth 但我得到了同样的错误。

UPDATE: I have done this and it seemed to work:更新:我已经这样做了,它似乎有效:

    componentDidUpdate() {
        this.updateFiltersHandler();
    }

    updateFiltersHandler = () => {
        if (this.filtersForIntialState.length === this.state.filters.length) {
            return;
        } else {
            this.setState({ filters: this.filtersForIntialState });
        }
    };

Also, I replace this from my previous code:另外,我用我以前的代码替换了它:

            const filtersForIntialState = filterBreedFor
                .concat(
                    mainTemperamentsFiltersNoDuplicates,
                    advancedTemperamentFiltersNoDuplicates
                )
                .map((filter) => {
                    return { name: filter, isChecked: false };
                });

            this.updateFiltersHandler(filtersForIntialState); 

with this:有了这个:

            this.filtersForIntialState = filterBreedFor
                .concat(
                    mainTemperamentsFiltersNoDuplicates,
                    advancedTemperamentFiltersNoDuplicates
                )
                .map((filter) => {
                    return { name: filter, isChecked: false };
                });

You are setting the state insider render() which is forbidden.您正在设置 state insider render() 这是被禁止的。 Instead, call a function, check if the state is different than what you want it to be, and if so, update it.相反,请拨打 function,检查 state 是否与您想要的不同,如果不同,请更新它。 If not - return from function and don't change the state.如果不是 - 从 function 返回并且不要更改 state。

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

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