【问题标题】:Uncaught TypeError: *** is not a function in a React component未捕获的 TypeError:*** 不是 React 组件中的函数
【发布时间】:2019-02-20 17:02:35
【问题描述】:

我在 React 组件的构造函数中传递一个对象作为参数。然后,我想调用一个对象的函数,但得到这个错误信息:

Uncaught TypeError: _this.layout.getWbsLayout is not a function
    at new Wbs (Wbs.tsx:50)
    at react-dom.js:4749
    at measureLifeCyclePerf (react-dom.js:4529)
    at ReactCompositeComponentWrapper._constructComponentWithoutOwner (react-dom.js:4748)
    at ReactCompositeComponentWrapper._constructComponent (react-dom.js:4734)
    at ReactCompositeComponentWrapper.mountComponent (react-dom.js:4642)
    at Object.mountComponent (react-dom.js:11542)
    at ReactCompositeComponentWrapper.performInitialMount (react-dom.js:4825)
    at ReactCompositeComponentWrapper.mountComponent (react-dom.js:4712)
    at Object.mountComponent (react-dom.js:11542)

我在构造函数中阅读了一些关于将方法绑定到 this 的帖子,但是当我调用作为参数传递的对象的函数时,我不确定这是否适用于此,并且仍然收到类似的消息说 bind is not a function .

这是我的代码,Wbs 是根 React 组件,WbsLayout 是我作为参数传递给 Wbs 构造函数的对象。

错误发生在构造函数中,当我执行this.layout.getWbsLayout() 请注意,我尝试调用 ComponentDidMount 中的函数,但得到了同样的错误。

import * as React from 'react';
import WbsLayout from "../layout/WbsLayout";

interface WbsProps {}
interface WbsState {
    wbsElements: any[];
    wbsEdges: any[]
}

class Wbs extends React.Component<WbsProps, WbsState>{

    public cy: Cy.Instance;
    private layout: WbsLayout;
    private s: snap.Paper;
    private renderer: WbsRenderer;

    public state : WbsState;

    constructor(props: WbsProps, layout: WbsLayout) {
        super(props);
        this.layout = layout;
        this.cy = this.layout.cy;

        // this does show a json object in the console, hence layout can be accessed
        console.log(layout.cy.elements().jsons());

        this.layout.getWbsLayout(); //The error happens here

        // initial state
        this.state = {
            wbsElements: [],
            wbsEdges: [],
        };
    }

    public render() {

        const wbsElements: any = this.state.wbsElements.map((element: any) => (
            <WbsElement
                key={element.wbsElementBox.nodeId}
                wbsElementBox={...element.wbsElementBox}
                wbsElementTitle={...element.wbsElementTitle}
                wbsElementId={...element.wbsElementId}
            />
        ));

        const wbsEdges: any = this.state.wbsEdges.map((edge: any) => (
            <WbsEdge
                key={edge.edgeId}
                edgeId={edge.edgeId}
                sourceWbsElementData={...edge.sourceWbsElementData}
                targetWbsElementData={...edge.targetWbsElementData}
            />
        ));

        return (
            <svg>
                {wbsElements}
                {wbsEdges}
            </svg>
        );
    }
}

export default Wbs;

这里是WbsLayout

导出类 WbsLayout {

    public cy: Cy.Instance;

    constructor(graph: any, Options?: Options) {

        this.cy = cytoscape({
            headless: true,
            elements: graph
        });

    }

    public getWbsLayout(): any {
        const wbsElements: any = this.cy.collection("node[visibility = 'visible']").map((n: Cy.CollectionNodes) =>
            ({
                wbsElementBox: {
                    nodeId: n.data().id,
                    x: n.data().x,
                    y: n.data().y,
                    width: n.data().width,
                    height: n.data().height
                },
                wbsElementTitle: {
                    text: n.data().title
                },
                wbsElementId: {
                    text: n.data().wbsId
                }
            })
        );

        const wbsEdges: any = [
            {
                edgeId: '5',
                sourceWbsElementData: {
                    nodeId: '1',
                    x:464.359375,
                    y:30,
                    width:100,
                    height:40,
                    layoutStyle: 0
                },
                targetWbsElementData: {
                    nodeId:'1.5',
                    x:867.875,
                    y:100,
                    width:130.84375,
                    height:40,
                    layoutStyle: 1
                }

            }
        ];

        return {
            wbsElements,
            wbsEdges
        };
    }

    ....
}
export default WbsLayout;

这是我实例化 Wbs 的方式:

let graph: any = {
    nodes: [],
    edges: []
};

let layout: WbsLayout = new WbsLayout(graph);
let wbs = new Wbs(null, layout);

我可以在 Wbs 的构造函数中看到 json 对象: console.log(layout.cy.elements().jsons());

【问题讨论】:

  • 认为您应该在渲染中执行 wbsElementswbsEdges 函数
  • 可能是因为React.createElement 在实例化您的组件时没有将WbsLayout 实例传递给您的构造函数。
  • 如何将layout 传递给构造函数?如果您想传递某些内容,请使用 props 做出反应。
  • 我刚刚编辑了我的帖子来回答你的问题。当我实例化时,我确实将布局传递给 Wbs,如果我在 Wbs 的构造函数中运行 console.log(...),我可以访问它。

标签: reactjs typescript


【解决方案1】:

编辑:问题被证明是无关的,但值得记住的是,React 非常擅长对这类事情发出早期警告,因为它会“测试”你的组件,如果事情没有发生则抛出错误或警告看起来'正确,例如,如果道具没有按预期进入。早期警告有时非常“很有帮助”,以至于它们可以摆脱你正常的调试本能。


原答案:

在 props 传入之前屏蔽函数调用不被执行,或者设置默认 props 设置某种虚拟或后备函数行为。

在构造函数中:

if (this.layout.getWbsLayout) {
  this.layout.getWbsLayout();
}

其他选项:

  • 为函数定义一个默认值。
  • 根据需要执行componentWillMountcomponentDidMount中的函数。生命周期钩子是执行数据实例化的正确位置。构造函数最适合状态和静态调用,例如根据需要绑定类的函数。

【讨论】:

  • 我试图在 componentDidMount 内调用但没有成功,同样的错误:componentDidMount() { let layout: any = this.layout.getWbsLayout(); this.setState( { wbsElements: layout.wbsElements, wbsEdges: layout.wbsEdges } ); }
  • 您是否尝试过if 方法——甚至可以通过查看typeof 使测试更加具体。我不会长期使用这种方法,但它可以帮助您缩小问题的根本原因。如果您至少在此处将代码减少到重现问题所需的最低限度,这也会有所帮助。这里有很多代码,但实际上只有大约 5-10 行看起来相关,但也许还有更多我遗漏的代码。
  • 感谢您的帮助本。基本上,尽管我能够 console.log 布局,但它没有通过,正如上面提到的 Nitzan 和 Andrew。我进行了一些重构,并通过道具传递了布局,现在它就像一个魅力。顺便说一句,听从您的建议,并在 componentWillMount 中执行我的数据实例化。
  • @GregForel 很高兴听到这个消息!我们以前都去过那里。你认为问题与你正在做的新事物有关……至少我是这样的!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-15
  • 2020-04-15
  • 1970-01-01
  • 1970-01-01
  • 2017-09-24
  • 2020-10-05
相关资源
最近更新 更多