【问题标题】:Why do 3 different component instances seem to be sharing state?为什么 3 个不同的组件实例似乎在共享状态?
【发布时间】:2020-09-07 00:15:01
【问题描述】:

我有一个令人难以置信的问题,这三个<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 对象。每个组件实例不应该有自己的状态吗?

这里是&lt;RecordAdmin&gt; 组件的来源:

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 时,我看到在页面加载时加载的第一个 &lt;RecordAdmin&gt; 正在将其记录输出到控制台,无论当前选择了哪个 &lt;RecordAdmin&gt; 实例。

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>
    );
}

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

【问题讨论】:

  • 您可以通过控制台登录构造函数来验证是否在所有三个路由中都使用了相同的组件实例。为每个添加一个唯一的 key 应该可以解决问题并通知 react 它确实应该是一个新的组件实例,而不仅仅是道具的更改。

标签: reactjs


【解决方案1】:

您可以为RecordAdmin 的每个实例使用不同的key,并且可以通过exact={true} 来确定。

【讨论】:

  • RecordAdmin 的每个实例上使用唯一的密钥道具解决了这个问题,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-25
  • 1970-01-01
  • 2014-08-13
  • 2012-02-10
  • 1970-01-01
  • 2020-08-02
相关资源
最近更新 更多