【问题标题】:Passing handler results in undefined传递处理程序导致未定义
【发布时间】:2017-08-25 07:41:50
【问题描述】:

我似乎无法正确传递此处理程序。 TabItem 以 undefined for onClick 结束。

搜索标签

export default class SearchTabs extends Component {
constructor(props) {
    super(props)
    const breakpoints = {
      [SITE_PLATFORM_WEB]: {
        displayGrid: true,
        autoFocus: true,
      },
      [SITE_PLATFORM_MOBILE]: {
        displayGrid: false,
        autoFocus: false,
      },
    };

    this.state = {
      breakpoints,
      filters: null,
      filter: null,
      isDropdownOpen: false,
      selectedFilter: null,
      tabs: null,
    };

    this.tabChanged = this.tabChanged.bind(this);
    this.closeDropdown = this.closeDropdown.bind(this);
  }
  ... more code

    createTabs(panels) {
        if(!panels) return;
        const tabs = panels.member.map((panel, idx) => {

          const { selectedTab } = this.props;
          const { id: panelId, headline } = panel;
          const url = getHeaderLogo(panel, 50);
          const item = url ? <img src={url} alt={headline} /> : headline;

          const classname = classNames([
            searchResultsTheme.tabItem,
            (idx === selectedTab) ? searchResultsTheme.active : null,
          ]);

          this.renderFilters(panel, idx, selectedTab);

          return (
            <TabItem
              key={panelId}
              classname={classname}
              idx={idx}
              content={item}
              onClick={this.tabChanged(idx, headline)}
            />
          );
        });

        return tabs;
      }

      tabChanged(idx, headline) {
        const { selectedTab } = this.props;
        const { selectedFilter } = this.state;
        const selectedFilterIdx = _.get(selectedFilter, 'idx', null);
        if (selectedTab !== idx) {
          this.props.resetNextPage();
          this.props.setTab(idx, selectedFilterIdx, headline);
          this.closeDropdown();
        }
      }
  render() {
    // const { panels, selectedTab } = this.props;
    // if (!panels || panels.length === 0) return null;
    //
    //
    // const { tabs, selectedTab } = this.props;

    return (
      <div>
        <ul>{this.state.tabs}</ul>
      </div>
    );
  }
}

export const TabItem = ({ classname, content, onClick, key }) => (
      <li key={key} className={`${classname} tab-item`} onClick={onClick} >{content}</li>
    );

所以在 TabItem onClick={onClick} 中以 undefined 结束 onClick。

更多信息

当这是父容器中的一个函数时,这是它的工作原理:

// renderDefaultTabs() {
  //   const { panels, selectedTab } = this.props;
  //
  //   if (!panels || panels.length === 0) return;
  //
  //   let filter = null;
  //
  //   const tabs = panels.member.map((panel, idx) => {
  //     const { id: panelId, headline } = panel;
  //     const url = getHeaderLogo(panel, 50);
  //     const item = url ?
  //       <img src={url} alt={headline} /> : headline;
  //     const classname = classNames([
  //       searchResultsTheme.tabItem,
  //       (idx === selectedTab) ? searchResultsTheme.active : null,
  //     ]);
  //
  //     filter = (idx === selectedTab) ? this.renderFilters(panel) : filter;
  //
  //     return (
  //       <li
  //         key={panelId}
  //         className={classname}
  //         onClick={() => {
  //           this.tabChanged(idx, headline);
  //         }}
  //       >
  //         {item}
  //       </li>
  //     );
  //   });

所以我将其提取到 SearchTabs 中,包括将 tabChange d 方法移动到我的新 SearchTabs 组件中。现在在容器中,上面现在这样做了:

  renderDefaultTabs() {
    const {
      onFilterClick,
      panels,
      resetNextPage,
      selectedTab,
      selectedFilter,
      isDropdownOpen,
    } = this.props;

    return (<SearchTabs
      panels={panels}
      ...
    />);
  }

注意:renderDefaultTabs() 作为 props 发送到容器的 render() 中,搜索会回调它,从而在搜索的 render() 中渲染它:

容器

render() {
    return (
      <Search
        request={{
          headers: searchHeaders,
          route: searchRoute,
        }}
        renderTabs={this.renderDefaultTabs}
        renderSearchResults={this.renderSearchResults}
        handleInputChange={({ input }) => {
          this.setState({ searchInput: input });
        }}
        renderAltResults={true}
      />
    );
  }

搜索是我们的应用使用的共享组件。

更新

所以我提到了 Container 的 render() 将 renderDefaultTabs 函数作为道具传递给 &lt;Search /&gt;。在&lt;Search /&gt; 内部,它最终会这样做:render() { &lt;div&gt;{renderTabs({searchResults})}&lt;/div&gt;} 调用容器的 renderDefaultTabs 函数,正如您在上面看到的,最终呈现

所以它把它作为一个函数传递。当我点击一个 TabItem 时,这很奇怪,它并没有点击我的 tabChanged 函数

更新

天啊,它正在击中我的 tabChanged。 Errr..我觉得我很好。谢谢大家!

【问题讨论】:

标签: javascript reactjs


【解决方案1】:

onClick={this.tabChanged(idx, headline)}

这不是将函数传递给子组件的props 的正确方法。喜欢就做(虽然不推荐)

onClick={() =&gt; this.tabChanged(idx, headline)}

更新

我想添加更多解释。通过onClick={this.tabChanged(idx, headline)},您正在执行tabChanged并将其返回值传递给onClick

使用您之前的实现:onClick={() =&gt; { this.tabChanged(idx, headline); }},现在onClick 将是一个类似于:

onClick = {(function() {
  this.tabChanged(idx, headline);
})}

所以它适用于您之前的实现。 使用您的新实现,onClick={() =&gt; this.tabChanged(idx, headline)} 应该可以工作

【讨论】:

  • 为什么不推荐?
  • 箭头函数() =&gt; 将在每个render 上创建一个全新的函数。您可以参考这里:github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/… 正确地做它
  • onClick={() =&gt; this.tabChanged(idx, headline)} - 不行,我试过了,还是没有定义。
  • 又是我的错。您无需执行该额外步骤,因为map 已经具有箭头功能。
  • 我添加了更多解释。从我的角度来看,箭头功能应该可以工作。你真的试过吗?
猜你喜欢
  • 2021-10-22
  • 2020-06-25
  • 2011-04-26
  • 1970-01-01
  • 2020-03-11
  • 2014-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多