使用react-redux在搜索表单中超出最大更新深度

问题描述 投票:0回答:1

由于react-redux中的无限循环,我很头疼,我不知道是什么原因造成的,请帮忙!!!

我正在尝试提交用户状态(是/否)这是我的表单的样子

在此输入图片描述

这是我的文件的结构 用户文件夹

  • SearchForms.js
  • 用户.js
  • 用户表.js

这是我最终遇到的运行时错误: 超出最大更新深度。当组件在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState 时,可能会发生这种情况。 React 限制嵌套更新的数量以防止无限循环。

SearchForm.js


import React, {Component, useRef} from "react";
import axios from "axios";
import {connect} from 'react-redux';
import {doToggleLoadClients, doUpdateSearchClientsOptions} from '../../apps/actions'

const getUsers = async (searchOption) => {

    const {page, userName, active} = searchOption;
    const searchParams = `?page=${page}&userName=${userName}&active=${active}`;

    return await axios.get(
        process.env.REACT_APP_WP_API + process.env.REACT_APP_GET_USERS + searchParams
    );
};

class SearchForm extends Component {

    constructor(props) {
        super(props);

        this.state = {
            userName: '',
            companyName: '',
            active: '',
            allUsers: [], //{"clients":[{}..{}],"total":123}
            userNameSuggestionsList: [],
            isDataReady: false
        };

        this.handleSubmit = this.handleSubmit.bind(this);
        this.handleClearResults = this.handleClearResults.bind(this);
    }

    /// -- Common events ----

    // update the the table when first load
    async componentDidMount() {

        const searchOption = {page: 'all'}
        const responseData = await getUsers(searchOption);
        this.setState({allUsers: responseData.data.clients});

    }

    handleSubmit = async (event) => {

        event.preventDefault();
        const searchOptions = this.state;
        this.props.onUpdateSearchClientsOptions(searchOptions);
        this.props.onToggleLoadClientsFlag();
        console.log("Searching for search form:", searchOptions);
    };

    handleClearResults = () => {
        this.setState({
            companyName: "",
            userName: "",
            clientStatus: ""
        });
    };

    handleUserStatusChange = event => {
        this.setState({[event.target.name]: event.target.value});
    };

   

    render() {
        const {
            userName,
            userNameSuggestionsList
        } = this.state;

        const userNameInputProps = {
            placeholder: 'Search User Name',
            value: userName,
            onChange: this.onUsernameChange
        };

        return (
            <Form onSubmit={this.handleSubmit}>
                <Form.Group as={Row}>
                    <Form.Label column sm="2" className="text-right label">
                        User Name
                    </Form.Label>
                    <Col sm="9">
                        <Autosuggest
                            suggestions={userNameSuggestionsList}
                            onSuggestionsFetchRequested={this.onUsernameSuggestionsFetchRequested}
                            onSuggestionsClearRequested={this.onUsernameSuggestionsClearRequested}
                            getSuggestionValue={this.getSuggestionUserNameValue}
                            renderSuggestion={this.renderUserNameSuggestion}
                            inputProps={userNameInputProps}
                            theme={theme}
                        />
                    </Col>
                </Form.Group>

                <Form.Group as={Row}>
                    <Form.Label column sm="2" className="text-right label">
                        User Status
                    </Form.Label>
                    <Col sm="9">
                        <Form.Control
                            className="input"
                            as="select"
                            name="active"
                            value={this.state.active}
                            onChange={this.handleUserStatusChange}>
                            >
                            <option>ALL</option>
                            <option>Y</option>
                            <option>N</option>
                        </Form.Control>
                    </Col>
                </Form.Group>

                <Row>
                    <Col sm={2}/>
                    <Col sm={9}>
                        <Button type="submit" size="lg" onClick={this.handleSubmit}>
                            SEARCH
                        </Button>
                    </Col>
                </Row>
            </Form>
        );
    }
}

const mapStateToProps = state => ({
        searchOptions: state.searchClientsOption.searchOptions,
        userName: state.session.userName
    }
);

const mapDispatchToProps = dispatch => ({
    onToggleLoadClientsFlag: () => dispatch(doToggleLoadClients()),
    onUpdateSearchClientsOptions: searchOptions => dispatch(doUpdateSearchClientsOptions(searchOptions))
});

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(SearchForm);

Users.js

import React, {Component, useState} from "react";
import {Navigate  } from "react-router-dom";
import UsersTable from "./UsersTable";
import SearchForm from "./SearchForm";

// Search users
class Users extends Component {

    render() {

        if (!this.props.id ) {
            return <Navigate to={"/admin/login"} />;
        }

        return (
            <div className="my-account">
                <Navbar {...this.props} handleLogin={this.props.handleLogin} />
                <Container>
                    <Row>
                        <Col md={12} className="mx-auto">
                            <h2 className="text-monospace font-weight-bold text-left mt-3">
                                Users
                            </h2>
                            <Card className="text-left">
                                <Card.Header className="card-header-account text-light">
                                    Search
                                </Card.Header>
                                <Card.Body>
                                    <SearchForm />
                                </Card.Body>
                            </Card>
                        </Col>
                    </Row>
                    <Row>
                        <Col md={12} className="mx-auto">
                            <Card className="my-5 text-left">
                                <Card.Header className="card-header-account text-light">
                                    Results
                                </Card.Header>
                                <Card.Body>
                                    <UsersTable handleLogin={this.props.handleLogin} />
                                </Card.Body>
                            </Card>
                        </Col>
                    </Row>
                </Container>
            </div>
        );
    }
}

export default Users;

UsersTable.js

import React, {Component} from "react";
import axios from 'axios';
import {connect} from 'react-redux';
import {doSetOptions} from '../../apps/actions';
import {doToggleLoadClients} from '../../apps/actions';

/**
 * Calling api users
 * @param searchOption
 * @returns {Promise<AxiosResponse<any>>}
 */
const getUsers = async (searchOption) => {

    const {userName, active, page, orderBy, descAsc } = searchOption;
    const searchParams = `?page=${page}&orderBy=${orderBy}&descAsc=${descAsc}&userName=${userName}&active=${active}`;

    return await axios.get(
        process.env.REACT_APP_WP_API + process.env.REACT_APP_GET_USERS + searchParams
    );
};

/**
 *
 * @param self
 * @returns {Promise<boolean>}
 */
const submitUpdateUser = async (self) => {

    const {updateId, active, updateUseName } = self.state;
    let userName = updateUseName;
    let id = updateId;
    const response = await axios.post(
        process.env.REACT_APP_WP_API + process.env.REACT_APP_UPDATE_USER,
        {
            id,
            userName,
            active
        }
    );

    if (response.data.error) {
        this.setState({error: response.data.error.text});
        return false;
    }
    else {
        return true;
    }
};

class UsersTable extends Component {

    constructor(props) {
        super(props);

        this.state = {
            clients:[],
            errors: [],
            page: 0,
            total: 0,
            limit: 10,
            orderBy: "id",
            isDataReady: false,
            error: "",
            dsc_userName: false,
            dsc_active: false,
            dsc_id: true,
            showModal:false,

            updateId: '',
            updateUseName:'',

            errorSubmit: false,
        };

        this.handleSort = this.handleSort.bind(this);
        this.handleClick = this.handleClick.bind(this);
        this.handleNext = this.handleNext.bind(this);
        this.handlePrevious = this.handlePrevious.bind(this);
        this.updateTable = this.updateTable.bind(this);

        this.handleSubmit = this.handleSubmit.bind(this);
        this.handleCloseModal = this.handleCloseModal.bind(this);
        this.handleShowModal = this.handleShowModal.bind(this);
        this.handleChange = this.handleChange.bind(this);
    }

    // update the table when submit search form
    async updateTable() {
        const descAsc = this.state["dsc_" + this.state.orderBy] ?"asc": "desc";
        const extraOptions = { page: this.state.page, orderBy: this.state.orderBy, descAsc: descAsc }
        const searchOptions = {...this.props.searchOptions, ...extraOptions};
        const response = await getUsers( searchOptions);

        this.setState({
            clients: response.data.clients, total: response.data.total, isDataReady: true
        });
    }

    // update the table when submit search form
    componentDidUpdate() {
        const { loadNewData } = this.props;

        if (loadNewData) {
            this.setState({
                page: 0
            }, () => this.updateTable());
        }
    }

    // update the the table when first load
    async componentDidMount() {

        this.setState({ isDataReady: false });
        const searchOptions = this.props.searchOptions;
        const response = await getUsers(searchOptions);

        this.setState({
            clients: response.data.clients,
            total: response.data.total,
            isDataReady: true
        });
    }

    handleShowModal(id, userName, active) {
        this.setState({
            updateId: id,
            updateUseName:userName,
            active:active,
            showModal: true,
            errorSubmit: false
        });
    }

    handleChange = event => {
        this.setState({ [event.target.name]: event.target.value, errorSubmit: false });
    };

    handleSubmit = async event => {

        event.preventDefault();
        const self = this;
        //console.log('Update user info submitted:', this.state);

        await this.setState({ errors: []});
        let success = await submitUpdateUser(self);
        if( success ) {
            alert('User info already updated!');
            await this.updateTable();
        }

        this.handleCloseModal();
    };

    render() {

        const { clients, isDataReady } = this.state;
        const pageCount = Math.ceil(parseInt(this.state.total) / 100);

        let errMsg;
        errMsg = this.state.errorSubmit && (
            <Alert variant = 'danger' >
                <ul>
                    <li>Please select the Customer Status</li>
                </ul>
            </Alert>
        );

        const header = (
            <thead>
                <tr>
                    <th>User ID
                        &nbsp;
                        <SortButton
                            id="id"
                            handleSort={this.handleSort}
                            btnSort={this.state.dsc_id ? "fas fa-caret-down" : "fas fa-caret-up"}
                        />
                    </th>
                    <th>User Name
                        &nbsp;
                        <SortButton
                            id="id"
                            handleSort={this.handleSort}
                            btnSort={this.state.dsc_userName ? "fas fa-caret-down" : "fas fa-caret-up"}
                        />
                    </th>
                    <th>Company</th>
                    <th>Email</th>
                    <th>Phone</th>
                    <th>Status
                        &nbsp;
                        <SortButton
                            id="active"
                            handleSort={this.handleSort}
                            btnSort={this.state.dsc_active ? "fas fa-caret-down" : "fas fa-caret-up"}
                        />
                    </th>
                </tr>
            </thead>
        );

        if (!isDataReady) {
            return (
                <Table striped bordered hover>
                    {header}
                    <tbody>
                    <tr>
                        <td colSpan="8">Loading ...</td>
                    </tr>
                    </tbody>
                </Table>
            );
        }

        if (clients.length === 0) {
            return (
                <div className="OrdersTable">
                    No records found
                </div>
            )
        }

        return (
            <div className="OrdersTable">
                <Footer
                    page={this.state.page}
                    total={this.state.total}
                    offset={100}
                    handleClick={this.handleClick}
                    handleNext={this.handleNext}
                    handlePrevious={this.handlePrevious}
                    pageCount={pageCount}
                />

                <Modal show={this.state.showModal} onHide={this.handleCloseModal} size="lg">
                    <Modal.Header closeButton>
                        <Modal.Title>Update Customer Info</Modal.Title>
                    </Modal.Header>
                    <Form onSubmit={this.handleSubmit}>
                        <Modal.Body>
                            <Form.Group as={Row}>
                                <Form.Label column sm="2" className="text-right label">
                                    Status
                                </Form.Label>
                                <Col sm="9">
                                    <Form.Control
                                        className="input"
                                        as="select"
                                        name="active"
                                        placeholder="Select One"
                                        value={this.state.active}
                                        onChange={this.handleChange}
                                    >
                                        <option>Select One</option>
                                        <option>Y</option>
                                        <option>N</option>
                                    </Form.Control>
                                </Col>
                            </Form.Group>

                            {errMsg}

                        </Modal.Body>

                        <Modal.Footer>
                            <Button variant="secondary" onClick={this.handleCloseModal}>
                                Cancel
                            </Button>
                            <Button variant="primary" type="submit">
                                Update Changes
                            </Button>
                        </Modal.Footer>
                    </Form>
                </Modal>

                <Table striped bordered hover>
                    {header}

                    <tbody id={'usersTableBody'} >
                        {clients.map(item => (
                            <tr key={item.id}>
                                <td>{item.id}</td>
                                <td>{item.userName}</td>
                                <td>{item.companyName}</td>
                                <td>{item.email}</td>
                                <td>{item.phone}</td>
                                <td>{item.active}</td>
                                <td>
                                    <Button variant="primary" onClick={() =>
                                        this.handleShowModal(
                                            item.id, item.userName, item.active
                                        )} >Edit
                                    </Button>
                                </td>
                            </tr>
                        ))}
                    </tbody>
                </Table>

                <Footer
                    page={this.state.page}
                    total={this.state.total}
                    offset={100}
                    handleClick={this.handleClick}
                    handleNext={this.handleNext}
                    handlePrevious={this.handlePrevious}
                    pageCount={pageCount}
                />
            </div>
        );
    }
}

const mapStateToProps = state => (
    {
        searchOptions: state.searchClientsOption.searchOptions,
        userName: state.session.userName,
        active: state.session.active,
        loadNewData: state.searchClientsOption.loadNewData,
    }
);

const mapDispatchToProps = dispatch => ({
        onToggleLoadClientsFlag: () => dispatch(doToggleLoadClients()),
        setOptions: options => dispatch(doSetOptions(options))
    }
);


export default connect(
    mapStateToProps,
    mapDispatchToProps
)(UsersTable);

react-redux
1个回答
0
投票

几天后,我发现这行代码导致了无限循环,不知何故,loadNewData值不断地来回无限地改变值。

const { loadNewData } = this.props;

    if (loadNewData) {
        this.setState({
            page: 0
        }, () => this.updateTable());
    }

我的意图是仅在选项发生变化时更新表格,所以我所做的是

 if(prevProps.searchOptions != this.props.searchOptions) {

...... }

© www.soinside.com 2019 - 2024. All rights reserved.