【问题标题】:calling a function using ref value in ReactJS throws error在 ReactJS 中使用 ref 值调用函数会引发错误
【发布时间】:2017-09-27 10:35:08
【问题描述】:

我一直在学习 ReactJS,我编写了一个简单的程序,其中一些记录显示在一个列表中,每个记录都可以通过单击其删除按钮来删除。我的代码中有三个组件。 Store 调用 View 组件显示记录,View 调用 Action 组件删除任何记录。

现在的问题是,当我按下删除按钮删除任何记录时,我收到Uncaught TypeError: Cannot read property 'deleteRecord' of undefinederror。那么请告诉我的代码中可能存在什么问题?

错误:

Uncaught TypeError: Cannot read property 'deleteRecord' of undefined
    at onClick (index.js:32647)
    at Object.ReactErrorUtils.invokeGuardedCallback (index.js:7735)
    at executeDispatch (index.js:7519)
    at Object.executeDispatchesInOrder (index.js:7542)
    at executeDispatchesAndRelease (index.js:5512)
    at executeDispatchesAndReleaseTopLevel (index.js:5523)
    at Array.forEach (<anonymous>)
    at forEachAccumulated (index.js:11731)
    at Object.processEventQueue (index.js:5723)
    at runEventQueueInBatch (index.js:26646)

代码:

index.html

<!DOCTYPE html>
<html lang = "en">
<head>
    <meta charset = "UTF-8">
    <title>React App</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
    <div id = "app"></div>
    <script src = "index.js"></script>
</body>
</html>

ma​​in.js

import React from 'react';
import ReactDOM from 'react-dom';
import Store from './Store.jsx';

ReactDOM.render(
    <Store />,
    document.getElementById('app')
);

Store.jsx

import React from 'react';
import View from './View.jsx';

class Store extends React.Component {

    constructor() {
        super();

        this.state = {
            records: [
                {
                    id: 1,
                    name: 'First User',
                },
                {
                    id: 2,
                    name: 'Second User',
                },
                {
                    id: 3,
                    name: 'Third User'
                }
            ]
        }

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

    updateStore(newState) {
        this.setState({records: newState});
    };

    render() {
        return (
            <div>
                <View store={this.state.records} updateStore={this.updateStore} />
            </div>
        );
    }
};

export default Store;

View.jsx

import React from 'react';
import Action from './Action.jsx';

class View extends React.Component {
    render() {
        return (
            <div className="container">
                <ul className="list-group">
                    {this.props.store.map((eachRecord,index) =>
                        <ListItem key={index} actionHandler={this.refs.actionHandler} singleRecord={eachRecord} />
                    )}
                </ul>
                <Action ref="actionHandler" store={this.props.store} updateStore={this.props.updateStore} />
            </div>
        );
    }
}

class ListItem extends React.Component {
    render() {
        return (
            <li className="list-group-item">
                {this.props.singleRecord.name}
                <button style={{float:'right'}} onClick={() => this.props.actionHandler.deleteRecord(this.props.singleRecord)}>Delete</button>
            </li>
        );
    }
}

export default View;

Action.jsx

import React from 'react';

class Action extends React.Component {
    render() {
        return (
            <div></div>
        );
    };

    deleteRecord(record) {
        var newStore = this.props.store.filter(eachR => eachR !== record);
        this.props.updateStore(newStore);
    }
}

export default Action;

【问题讨论】:

标签: reactjs


【解决方案1】:

在 react 附加组件的引用之前,您正在使用 refs 对象。 react 建议不要再像这样使用refs,而是使用带有回调的ref&lt;div ref={ref =&gt; this.divRef = ref} /&gt; https://facebook.github.io/react/docs/refs-and-the-dom.html

但在你的情况下,你可以通过将回调传递给组件来做到这一点,而根本不使用refs。 首先,&lt;Actions /&gt; 组件似乎是不必要的。 您可以将回调函数传递给&lt;ListItem /&gt; 组件:

class ListItem extends React.Component {

  deleteRecord(record) {
    var newStore = this.props.store.filter(eachR => eachR !== record);
    this.props.updateStore(newStore);
  }

  render() {
    return (
      <li className="list-group-item">
        {this.props.singleRecord.name}
        <button style={{ float: 'right' }} onClick={() => this.deleteRecord(this.props.singleRecord)}>Delete</button>
      </li>
    );
  }
}

现在,当您单击此按钮时,此组件将知道该做什么。

请注意,现在您需要将所有这些道具传递给 &lt;ListItem /&gt; 组件,如下所示:

&lt;ListItem key={index} store={this.props.store} updateStore={this.props.updateStore} singleRecord={eachRecord} /&gt;

为了获得更好的方法和更少的传递道具,您可能希望将 deleteRecord 函数放在顶级组件中,然后传递该组件。 更多信息可以在这里阅读:https://facebook.github.io/react/docs/lifting-state-up.html

【讨论】:

  • 由于某些原因,我必须使用&lt;Action /&gt; 组件。您能否在不更改代码结构的情况下提出解决方案?
猜你喜欢
  • 2018-11-06
  • 1970-01-01
  • 1970-01-01
  • 2020-09-26
  • 1970-01-01
  • 2019-06-16
  • 2013-07-23
  • 1970-01-01
  • 2021-02-19
相关资源
最近更新 更多