Search code examples
javascriptreactjscallbackreact-props

passing function as a prop to child component in React throws error


Are there any specific guidelines when passing callbacks as props to child components in React?

At some point my code ina app.js looks the following:

test() {
  
}
  render(){
  return (
    <div className="App">
      <MiniDrawer handleProductChange={this.handleProductChange.bind(this)} product={{icon:'', name:'Magnifier', height:'20px'}}/>
      <div className='inrow'> 
      <PowerbiEmbedded
          id={this.state.ReportId}
          embedUrl={"https://app.powerbi.com/reportEmbed?reportId="+this.state.ReportId+"&groupId="+this.state.workspaceId}
          accessToken={this.state.accesstoken}
          filterPaneEnabled={true}
          navContentPaneEnabled={true}
          bookmarksPaneEnabled={true}
         test={() => this.test}
          //pageName={`${YOUR_PAGE_ID}`}
          //embedType={`Report`}
          tokenType={0}
          width='100%'
          height='1000px'
        />
    </div>
    </div>
    
  );}

The MiniDrawer component does not signal any issues with handleProductChange callback. While simple callback which I am trying to pass to PowerBiEmbedded component fails with error:

DataCloneError: Failed to execute 'postMessage' on 'Window': () => this.test could not be cloned. I managed to extract the source of the problem. There is a function inside the child component using props with Object.assign. If i comment out this function error disappears. What can I do about it?

updateState (props) {
    const nextState = Object.assign({}, this.state, props, {
      pageName: this.props.pageName,
      settings: {
       /* panes:{
          bookmarks: {visible: this.props.bookmarkPaneEnabled},
          filters: {visible: this.props.filterPaneEnabled},
          pageNavigation: {visible: this.props.navContentPaneEnabled}
        },*/
        filterPaneEnabled: this.props.filterPaneEnabled,
        navContentPaneEnabled: this.props.navContentPaneEnabled,
        bookmarkPaneEnabled: this.props.bookmarkPaneEnabled,
        layoutType: this.props.mobile ? pbi.models.LayoutType.MobilePortrait : undefined
      },
      type: this.props.embedType ? this.props.embedType : 'report'
    })

Any ideas what am I missing in here?


Solution

  • Ok. Found the solution. Object assign method for some reason fails to copy react callback '[native code]' issue. I'll let the purist to debate on that. I do not need the callback in this new object as it is passed further, and it is intended to have other properties, I simply clone the props myself with function removed ("zonk") in the example. Obviously this could be extended to verify the typeof key to make it more generic.

    updateState (props) {
      var distilledProps = _objectWithoutProperties(props, ['zonk'])
      console.log(distilledProps)
        const nextState = Object.assign({}, this.state, distilledProps, {
          pageName: this.props.pageName,
          settings: {
           /* panes:{
              bookmarks: {visible: this.props.bookmarkPaneEnabled},
              filters: {visible: this.props.filterPaneEnabled},
              pageNavigation: {visible: this.props.navContentPaneEnabled}
            },*/
            filterPaneEnabled: this.props.filterPaneEnabled,
            navContentPaneEnabled: this.props.navContentPaneEnabled,
            bookmarkPaneEnabled: this.props.bookmarkPaneEnabled,
            layoutType: this.props.mobile ? pbi.models.LayoutType.MobilePortrait : undefined
          },
          type: this.props.embedType ? this.props.embedType : 'report'
        })
    

    ... and helper function:

    function _objectWithoutProperties(obj, keys) {
      var target = {};
      for (var i in obj) {
        if (keys.indexOf(i) >= 0) continue;
        if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
        target[i] = obj[i];
      }
      return target;
    }