如何将方法传递给子反应组件?

时间:2016-02-03 16:12:31

标签: reactjs

人们! 我开始使用webpack,react,redux等构建应用程序。我不确定我是否应该面对我应该的情况:

我想开发一个单页应用程序,只有一个反应节点"< myApp />"这将包含内部的一切。我的页面上会出现的第一件事是引导导航栏。我想要的是创建一个反应组件,渲染导航栏并传递给他1)一个字符串列表,和2)一个函数,当点击其中一个项目时应该调用。我想以这种方式做到这一点,因为我想在顶层跟踪"页面"我在哪里(它将始终是导航栏项目之一)。

这是我的myApp组件:

export default class myApp extends React.Component {
    constructor(props) {
        super(props);
        this.handleNavbarClick = ::this.handleNavbarClick;
        this.state = {
            currentPage: 'Home',
            navbarItems : ['Home', 'contact', 'etc']
        };
    }
    handleNavbarClick(e) {
        //debug alert:
        alert(e);
        this.state.currentPage = e;
    }
    render() {
        return (
            <div>
                <NavBar items={this.state.navbarItems} itemClickHandler={this.handleNavbarClick}/>
                <Wellcome />
                <LandingMenu />
                CurrentPage: {this.state.currentPage}
            </div>
        );
    }
}

这里是我的导航栏组件:

export default class NavBar extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        var handler = this.props.itemClickHandler;
        var itemsHtml = this.props.items.map(function(i) {
            return <li className="nav-item"> <a className="nav-link" onClick={handler(i)}>{i}</a></li>
        });
        return (
             <nav className="navbar navbar-static-top navbar-dark bg-inverse">
              <a className="navbar-brand" href="#"><img src={LogoSrhSmall} /></a>  
              <ul className="nav navbar-nav">
                {itemsHtml} 
              </ul>
            </nav>

        )
    }
}

实际上,当我点击其中一个导航栏项目时,没有任何反应,但是当页面加载时,会自动为每个项目调用函数handleNavbarClick的警报,我不明白为什么:(

有人可以告诉我,我做错了什么?我正确地面对问题?

提前致谢,

约翰

@ janaka-stevens,@赞,谢谢!

从您的答案中应用一些更改,我可以通过将其存储在属性&#34; id&#34;并访问它抛出e.target.id。 对于这种情况来说这很好,但是不要使用简单的字符串,我想使用一系列更复杂的对象,让我们说:

[
    { name: 'home', url: '/someroute', importantData: {...} },
    { name: 'otherLink', url: '/someOtherroute' , importantData: {...} }
]

我想将完整的选定对象传递给父myApp?

目前,它看起来像是:

on myApp:

...
handleNavbarClick(e) {
        this.setState({currentPage : e.target.id}) ;
    }
...

并在NavBar上:

...
    renderNavItem(item) {
        return (<li className="nav-item">
            <a id={item} className="nav-link" onClick={this.props.itemClickHandler}>{item}</a>
        </li>)
    }
    render() {
        return (
             <nav className="navbar navbar-static-top navbar-dark bg-inverse">
              <a className="navbar-brand" href="#"><img src={LogoSrhSmall} /></a>  
              <ul className="nav navbar-nav">
                {this.props.items.map(this.renderNavItem, this)} 
              </ul>
            </nav>
        )
    }
...

但是如果在&lt; a&gt;标记,而不是使用:

 onClick={this.props.itemClickHandler}

我用:

 onClick={this.props.itemClickHandler(item)}

每次渲染迭代都会调用itemClickHandler,因为反应将会调用&#34;迭代项目以显示它们的方法(没有任何用户交互)....任何想法为什么?

提前致谢, 约翰

3 个答案:

答案 0 :(得分:1)

你有两个问题。第一个是handleNavbarClick(e)中的e是事件。您想要做的是为每个项目列表提供一个标识符。然后你会得到e.target.id。当然,您还需要在映射列表中添加id。第二个问题是你需要通过这个&#39;你的映射列表就像这样;

&#13;
&#13;
render() {
  var itemsHtml = this.props.items.map(function(i) {
    return <li className="nav-item"> <a id={i.id} className="nav-link" onClick={this.props.itemClickHandler}>{i}</a></li>
        }, this);
&#13;
&#13;
&#13;

注意地图中的第二个参数。

答案 1 :(得分:1)

我将建议您对代码进行一些更改,以使其更易于阅读:

对于itemClickHandler,您使用(e)以外的内容,因为e通常表示事件。为此,你应该itemClickHandler(page)

然后在Navbar组件中,你可能想要做这样的事情:

export default class NavBar extends React.Component {
    constructor(props) {
        super(props);
    }
    renderNavItem(item) {
        <li className="nav-item">
            <a className="nav-link" onClick={this.props.handleNavbarClick(item)}>{item}</a>
        </li>
    }
    render() {
        return (
             <nav className="navbar navbar-static-top navbar-dark bg-inverse">
              <a className="navbar-brand" href="#"><img src={LogoSrhSmall} /></a>  
              <ul className="nav navbar-nav">
                {this.props.items.map(this.renderNavItem)} 
              </ul>
            </nav>

        )
    }
}

但你做错的主要事情是你永远不会设置状态。

React中的#1规则是你永远不想改变道具或状态(通过做this.prop.whatever = blarthis.state.whatever = blar。如果你这样做,那么什么都不会改变,你可以改变组件。重新传递道具或状态可能没有正确的信息。所以如果你想改变状态,你必须拨打this.setState({currentPage: page})

因此,在handleNavbarClick内,您要将其更改为:

handleNavbarClick(page) {
    //debug alert:
    alert(page);
    this.setState({currentPage: page});
}

这将告诉React你已经改变了状态并希望重新渲染。

答案 2 :(得分:0)

我遇到的问题是处理程序自己运行而没有实际单击按钮。我用一个像你是第一个的参数调用处理程序。我删除了,行为停止了。我尝试了bind(null,props)技巧,它适用于道具,但我不知道如何在处理程序中访问事件本身,所以我可以e.preventDefault()。

在找了一分钟后,我找到了这个gem,它遍历函数收到的所有未命名参数。

for (var i=0; i<arguments.length; i++) {
      console.log(arguments[i])
    };

使用它,我可以使用

访问处理程序中的事件
e = arguments[1] 

现在一切都很顺利。

感谢您给我一个起点!