为什么3个不同的组件实例似乎处于共享状态?

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

我有一个令人难以置信的问题,其中所有这三个<RecordAdmin>组件实例似乎都使用页面加载时首先加载哪个组件的状态。

我不知道它是如何发生的,或者为什么,并且奇怪的是,它以前是起作用的。

            <Switch>
                <Route path="/admin/books">
                    <RecordAdmin singular="book" plural="books" table={BookTable} form={BookForm} />
                </Route>
                <Route path="/admin/authors">
                    <RecordAdmin singular="author" plural="authors" table={AuthorTable} form={AuthorForm} />
                </Route>
                <Route path="/admin/branches">
                    <RecordAdmin singular="branch" plural="branches" table={BranchTable} form={BranchForm} />
                </Route>
            </Switch>

使用console.log,似乎所有这三个组件将具有相同的this.state.records对象。每个组件实例都不应该有自己的状态吗?

这里是<RecordAdmin>组件的来源:

import React from "react";
import Axios from "axios";
import {
    Switch,
    Route,
    NavLink,
    Redirect
} from "react-router-dom";

class NewRecordForm extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            redirect: false,
        };
    }

    handleSubmit = (event, formFields, multipart = false) => {
        event.preventDefault();

        let formData = null;
        let config = null;
        if (multipart) {
            formData = new FormData();
            for (let [key, value] of Object.entries(formFields)) {
                formData.append(key, value)
            }
            config = {
                headers: {
                    'Content-Type': 'multipart/form-data'
                }
            }
        } else {
            formData = formFields;
        }

        Axios.post(`${process.env.REACT_APP_API_URL}/${this.props.plural}`, formData, config)
        .then(response => {
            this.setState({redirect: true})
        }).catch(error => {
            console.log(error)
        })
    }

    render() {
        if (this.state.redirect) {
            this.props.redirectCallback();
        }
        const Form = this.props.form
        return (
            <div>
                {this.state.redirect ? <Redirect to={`/admin/${this.props.plural}`} /> : null}
                <Form handleSubmit={this.handleSubmit} />
            </div>
        )
    }
}

function errorMessage(props) {
    return (
        <div class="alert alert-danger" role="alert">
            {props.msg}
        </div>
    )
}

export default class RecordAdmin extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            records: []
        }
    }

    componentDidMount() {
        this.loadRecords();
    }

    loadRecords = () => {
        Axios.get(process.env.REACT_APP_API_URL + '/' + this.props.plural)
        .then(response => {
            this.setState({records: response.data})
        }).catch(error => {
            console.log(error)
        })
    }

    deleteRecord = (event, recordId) => {
        event.preventDefault();
        Axios.delete(process.env.REACT_APP_API_URL + '/' + this.props.plural + '/' + recordId).then(response => {
            this.loadRecords();
        })
    }

    render() {
        // this allows us to pass props to children that are loaded via {this.props.children}
        // more on that here: https://medium.com/better-programming/passing-data-to-props-children-in-react-5399baea0356
        const TableComponent = this.props.table
        return (
            <div className="admin-body">
                {this.state.errorMessage ? <errorMessage msg={this.state.errorMessage} /> : null}
                <Switch>
                    <Route exact path={`/admin/${this.props.plural}`}>
                        <div className="admin-menu">
                            <NavLink className="btn btn-primary" to={`/admin/${this.props.plural}/new`}>New {this.props.singular.charAt(0).toUpperCase() + this.props.singular.slice(1)}</NavLink>
                        </div>
                        <TableComponent records={this.state.records} deleteRecord={this.deleteRecord} />
                    </Route>
                    <Route exact path={`/admin/${this.props.plural}/new`}>
                        <NewRecordForm plural={this.props.plural} form={this.props.form} redirectCallback={this.loadRecords}/>
                    </Route>
                </Switch>
            </div>
        );
    }
}

编辑:

[当我抛出console.log时,我看到无论页面当前选择了哪个<RecordAdmin>实例,页面加载时加载的第一个<RecordAdmin>都将其记录输出到控制台。

render() {
    // this allows us to pass props to children that are loaded via {this.props.children}
    // more on that here: https://medium.com/better-programming/passing-data-to-props-children-in-react-5399baea0356
    const TableComponent = this.props.table
    console.log(this.records) // No matter which <RecordAdmin> is currently being displayed, the records will be the records from whichever <RecordComponent was first loaded on page load.
    return (
        <div className="admin-body">
            {this.state.errorMessage ? <errorMessage msg={this.state.errorMessage} /> : null}
            <Switch>
                <Route exact path={`/admin/${this.props.plural}`}>
                    <div className="admin-menu">
                        <NavLink className="btn btn-primary" to={`/admin/${this.props.plural}/new`}>New {this.props.singular.charAt(0).toUpperCase() + this.props.singular.slice(1)}</NavLink>
                    </div>
                    {console.log(this.state.records)}
                    <TableComponent records={this.state.records} deleteRecord={this.deleteRecord} />
                </Route>
                <Route exact path={`/admin/${this.props.plural}/new`}>
                    <NewRecordForm plural={this.props.plural} form={this.props.form} redirectCallback={this.loadRecords}/>
                </Route>
            </Switch>
        </div>
    );
}

无论正在显示哪个<RecordAdmin>实例,使用console.log都表明状态正在所有3个<RecordAdmin>实例之间共享。

reactjs
1个回答
0
投票

您可以为key的每个实例使用不同的RecordAdmin,也许只是为了确保可以传递exact={true}

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