reactjs - Uavbrutt TypeError: *** er ikke en funksjon i en React-komponent


Jeg sender et objekt som et argument i konstruktøren til en React-komponent. Deretter vil jeg kalle en av objektets funksjoner, men får denne feilmeldingen:

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)

Jeg leste noen innlegg om å binde metoder til this i konstruktøren, men siden jeg kaller en funksjon til et objekt jeg sendte som et argument, er jeg ikke sikker på om dette gjelder her, og jeg fikk fortsatt en lignende melding som sier bind er ikke en funksjon.

Her er koden min, Wbs er roten React-komponenten, WbsLayout er et objekt jeg sender som en parameter til Wbs' konstruktør.

Feilen oppstår i konstruktøren, når jeg gjør this.layout.getWbsLayout() Merk at jeg prøvde å kalle funksjonen i ComponentDidMount i stedet, men fikk den samme feilen.

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;

Her er WbsLayout:

eksporter klasse 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;

Slik instansierer jeg Wbs:

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

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

Jeg kan se json-objekter i Wbs' konstruktør: console.log(layout.cy.elements().jsons());

Svar #1

REDIGER: Problemet viste seg å være urelatert, men det er verdt å huske at React er veldig god til å kaste tidlige advarsler om denne typen ting ved at den vil 'teste' komponentene dine og kaste feil eller advarsler hvis ting ikke 'ser' riktige ut, f.eks. hvis props ikke kommer inn som forventet. De tidlige advarslene er noen ganger så 'hjelpsomme' at de kan forstyrre dine vanlige feilsøkingsinstinkter.

Opprinnelig svar:

Enten skjerm funksjonskallet fra å bli utført før propsene blir sendt inn, eller sett standardprops som angir en slags dummy- eller fallback-funksjonsatferd.

I konstruktøren:

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

Andre alternativer:

  • definer en standardverdi for funksjonen.
  • utfør funksjonen i componentWillMount eller componentDidMount, avhengig av dine behov. Livssyklus-kroker er det riktige stedet å utføre data-instansiering. Konstruktøren er best for tilstand og statiske kall som å binde klassens funksjoner, etter behov.

Svar #2

Jeg hadde den samme feilmeldingen, og det ser ut som dette spørsmålet dukker opp som spørsmål nummer 1, så jeg vil bare skrive løsningen min her.

Jeg hadde denne koden:

 onClick={this.setSelected(item)}

og måtte endre det til dette:

 onClick={() => this.setSelected(item)}

Relaterte artikler