如何将绑定函数的参数传递给React子节点?

时间:2017-08-05 18:34:28

标签: javascript reactjs

我有一个React应用程序,它有子标签和显示。

<App>
    <Nav>
        <Tab1></Tab1>
        <Tab2></Tab2>
        <Tab3></Tab3>
    </Nav>
    <Section>Display Stuff Here</Section>
    <Footer></Footer>
</App>

当我在应用程序中创建选项卡时,我有一个for循环,它将选项卡附加到Map变量(它是App React组件的子代)中。

for(...) {
    tab = React.createElement(Tab, {changeDisplay: () => {this.handleClick(this.changeDisplay(i)}});
    myMap.set(i, tab);
}

它应该做的是传递从for-loop递增的i变量。我甚至做了一个console.log来确保它通过1,2,3,4。 但是,实际显示的是最后一个变量:4。

在Tab类中,我有权使用调用道具:

class Tab extends React.Component {
    constructor(props) {
        super(props);
        this.tab = React.Component('div', null);
    }
    render() {
        return this.tab;
    }
    componentDidMount() {
        this.forceUpdate();
    }
    componentWillUpdate(nextProps, nextState) {
        this.tab = React.Component('div', {onClick: nextProps.changeDisplay});
    }
}

对于每个Tab,changeDisplay的值应该是唯一的,因此Tab2应该只有一个值2,Tab3应该只有3,等等.for循环不应该将下一个值传递给任何以前已经创建的Tabs它们已经制作并附加到地图变量中。

关于如何使这项工作的任何建议?

我可以制作自定义功能:

changeDisplay1() { changeDisplay(1) };
changeDisplay2() { changeDisplay(2) };
changeDisplay3() { changeDisplay{3) };
changeDisplay4() { changeDisplay(4) };

但是,我想以正确的方式做,而不是制造黑客。

1 个答案:

答案 0 :(得分:0)

React非常强大,您可以找到多种基于父状态呈现组件列表的方法。这是我一起拉的快速版本。

您可以在此处查看工作副本:https://codesandbox.io/s/zzqLPrjO

说明:

我们创建一个父组件,用于存储可用选项卡和active tab等数据。我们通过从Library对象上的键创建数组来加载可用的选项卡。 (这完全是可选的,但可以更容易地添加其他标签)

将标签加载到父组件后,我还创建了一个设置/更改active tab的函数。这将传递到我们地图中的标签,该标签会呈现从Library对象中选取的每个标签。

在我们的Tab组件中,我们只渲染名称以及挂钩到我们的父组件的click事件,该事件会将active tab更改为已单击的选项卡。 (注意:注意我们如何在render方法中避免函数绑定,这样我们就不会在每次渲染组件时都创建一个新函数(这被认为是不好的做法,这就是为什么我要避免它。)

活动标签更改后,我们对Library进行基本查找,并将组件附加到该索引。

import React from 'react';
import { render } from 'react-dom';

// *---------------------
// | Tab Component
// *---------------------

const activeTab = {
  background: 'green',
}

class Tab extends React.Component {
  change = () => this.props.change(this.props.name)
  render = () => {
    const {
      name: NAME,
      active: ACTIVE,
    } = this.props;
    const isActive = ACTIVE === NAME ? activeTab : null;
    return <button style={isActive} onClick={this.change}>{this.props.name}</button>
  }
}
  
// *---------------------
// | Mock list of Components
// *---------------------
  
const Home = () => <div>Home</div>
const About = () => <div>About</div>

// *---------------------
// | Library of Components
// *---------------------

const Library = {
  Home,
  About
}

// *---------------------
// | Display Components
// *---------------------
  
const Display = ({screen}) => {
  const Comp = Library[screen];
  return screen === null ? <div>Please select a tab</div> : <Comp/>
}

// *---------------------
// | Main App
// *---------------------

class App extends React.Component {
  state = {
    tabs: [],
    activeTab: null,
  }
  componentWillMount() {
    const tabs = Object.keys(Library);
    this.setState({
      tabs: tabs
    });
  }
  changeTab = (tab) => {
    this.setState({ activeTab: tab });
  }
  render() {
    return (
      <div>
        { this.state.tabs.map((tab,index) => {
          return <Tab key={index} name={tab} active={this.state.activeTab} change={this.changeTab} />
        }) }
        <Display screen={this.state.activeTab} />
      </div> 
    )
  }
}

render(<App />, document.getElementById('root'));