开发者问题收集

React.js onClick 事件:TypeError:无法读取未定义的属性

2017-09-24
4331

目前学习 React 和 JavaScript 很困难。

我有两个组件, Navigation :

import React from 'react';
import ReactDOM from 'react-dom';
import Nav from './houses/Nav.js';

// set data
var navbar = {};
navbar.brand = {linkTo: "#hero", text: "text"};
navbar.links = [
      {linkTo: "#", event:"es", spanClassName: "flag-icon flag-icon-es"},
      {linkTo: "#", event:"en", spanClassName: "flag-icon flag-icon-gb"},
      {linkTo: "#about", text: "about", spanClassName: "btnicon icon-user"},
      {linkTo: "#contacts", text: "contacts", spanClassName: "btnicon icon-envelope-open"}
  ];

class Navigation extends React.Component {

  render() {
    return (
    <header>         
      <Nav {...navbar} />        
    </header>
    )
  }
}

module.exports = Navigation;

Nav :

import React from 'react';
import ReactDOM from 'react-dom';

class Nav extends React.Component {    

  render() {

    const changeLanguage = (lng) => {
      i18n.changeLanguage(lng);
    } 

      return(
        <nav className="navbar navbar-inverse navbar-fixed-top" role="navigation">
          <div className="container">
            <div className="navbar-header">
              <button type="button" className="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse" aria-expanded="false">
                <span className="sr-only" lang="lt">Toggle nav</span> 
                <span className="icon-bar"></span>
                <span className="icon-bar"></span>
                <span className="icon-bar"></span>
              </button>
              <NavBrand linkTo={this.props.brand.linkTo} text={this.props.brand.text} />
            </div>
            <div className="collapse navbar-collapse">
              <NavMenu links={this.props.links} />
            </div>
          </div>
        </nav>
      );
    }
  };

  class NavBrand extends React.Component{
    render() {
      return (
        <a className="navbar-brand" alt="back to home" href={this.props.linkTo}>{this.props.text}
            <span className="brandicon"></span> 
            <span className="brandname"></span>   
        </a>
      ); 
    }
  };

  class NavMenu extends React.Component{
    render() {
      var links = this.props.links.map(function(link){       
          return (
            <NavLink linkTo={link.linkTo} text={link.text} active={link.active} event={link.event} spanClassName={link.spanClassName} />
          );

      });
      return (
        <ul className="nav navbar-nav navbar-right">
          {links}
        </ul>
      );
    }
  };

  class NavLink extends React.Component{
   render() {        

    if (this.props.event){
      return(
        <li><button onClick={() => changeLanguage(this.props.event)}>{this.props.event}<span className={(this.props.spanClassName)}></span></button></li>
      )
    }
    return(        
      <li className={(this.props.active ? "active" : "")}><a href={this.props.linkTo}>{this.props.text} <span className={(this.props.spanClassName)}></span></a></li>
    );
  }
};


  module.exports = Nav;

目前我想只向具有语言属性的某些 <li> 元素添加自定义 onClick 事件。它应该呈现以下内容:

其他组件的 render() 内的工作 onClick 事件如下所示: onClick={() => changeLanguage('lang_attribute') 因此我应该通过导航渲染获得相同的结果

按下渲染按钮时,我收到错误消息: 未捕获的 TypeError:无法读取未定义的属性“changeLanguage”

需要一些有关工作示例的帮助

更新 看来我的问题主要与 18next 有关。我正在研究 i18n 文档(因为我还必须为菜单项进行翻译)并进行了一些尝试,但据我所知,问题出在 HOC 和 i18n 函数上。它们超出了范围,因为这里有几个类。 因此我收到两个错误:t 不是函数,i18n 未定义。

import React from 'react';
import ReactDOM from 'react-dom';
import {translate} from 'react-i18next';


class Nav extends React.Component {

  render() {

      return(
        <nav className="navbar navbar-inverse navbar-fixed-top" role="navigation">
          <div className="container">
            <div className="navbar-header">
              <button type="button" className="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse" aria-expanded="false">
                <span className="sr-only">Toggle</span> 
                <span className="icon-bar"></span>
                <span className="icon-bar"></span>
                <span className="icon-bar"></span>
              </button>              
              <NavBrand linkTo={this.props.brand.linkTo} text={this.props.brand.text} />
            </div>
            <div className="collapse navbar-collapse">
              <NavMenu links={this.props.links} />
            </div>
          </div>
        </nav>
      );
    }
  };

  class NavBrand extends React.Component{
    render() {

      return (
        <a className="navbar-brand" alt="back to home" href={this.props.linkTo}>{this.props.text}
            <span className="brandicon"></span> 
            <span className="brandname"></span>   
        </a>
      ); 
    }
  };

  class NavMenu extends React.Component{
    render() {

      const { t, i18n } = this.props;

      var links = this.props.links.map(function(link, index){         
          return (
            <PureNavLink  linkTo={link.linkTo} text={t(link.text)} active={link.active} event={link.event} spanClassName={link.spanClassName} />
            /*text={t(link.text)}*/  

          );

      });
      return (
        <ul className="nav navbar-nav navbar-right">
          {links}
        </ul>
      );
    }
  };

  class PureNavLink  extends React.Component{

    render() {        
      const { t, i18n } = this.props;
      const toggle = lng => i18n.changeLanguage(lng);       

      if (this.props.event){        

        return(  
          <div>               

          <button onClick={() => toggle(this.props.event)}>{t(this.props.event)}</button>          
          </div>        
        )
      }

      return(        
        <li className={(this.props.active ? "active" : "")}><a href={this.props.linkTo}>{this.props.text} <span className={(this.props.spanClassName)}></span></a></li>        
      );
    }
  };

  const NavLink = translate()(PureNavLink);
  module.exports = translate()(Nav);
3个回答

因此,您似乎在 Navrender() 方法内定义了 changeLanguage 函数。因此, changeLanguage 绑定到 Nav 的范围和上下文,因此您的 NavLink 组件对此一无所知。请先尝试将 changeLanguage 移出任何组件,然后查看它是否被调用,即

// define the function outside of component scope
const changeLanguage = (lng) => {
  i18n.changeLanguage(lng);
};

// function is now available for use in any component in
// this module - just export it to use it in other modules
class Nav extends React.Component {

  render() {
    // your code and other components
  }
}

React 组件中定义的方法和函数绑定到该组件的实例。在其他地方调用该函数或方法的唯一方法是 1) 在任何组件之外定义该函数,或 2) 将对该函数或方法的引用作为 prop 传递给您的子组件。如果执行第 2 步,请确保绑定原始组件的 this 上下文,否则您将收到如您所见的错误。

Parker Ziegler
2017-09-28

Parker 的答案是正确的

a)像上面的代码一样移动 changeLanguage - 但也要 import i18n from '../i18n'; 或您定义 i18n 实例的位置。

import i18n from 'i18n';

// define the function outside of component scope
const changeLanguage = (lng) => {
  i18n.changeLanguage(lng);
};

// function is now available for use in any component in
// this module - just export it to use it in other modules
class Nav extends React.Component {

  render() {
    // your code and other components
  }
}

或者 b)通过 props 将 changeLanguage 向下传递。

// ...
<NavMenu links={this.props.links} changeLanguage={changeLanguage} />

// ...
<NavLink changeLanguage={changeLanguage} linkTo={link.linkTo} text={link.text} active={link.active} event={link.event} spanClassName={link.spanClassName} />

或者 c)用翻译 hoc 装饰你的 NavLink

class PureNavLink extends React.Component{

    render() {        
      const { t, i18n } = this.props;
      const toggle = lng => i18n.changeLanguage(lng); 

      if (this.props.event){        

        return(  
          <div>               

          <button onClick={() => toggle(this.props.event)}>{t(this.props.event)}</button>
          </div>        
        )
      }

      return(        
        <li className={(this.props.active ? "active" : "")}><a href={this.props.linkTo}>{this.props.text} <span className={(this.props.spanClassName)}></span></a></li>        
      );
    }
  };

const NavLink = translate()(PureNavLink);

https://react.i18next.com/components/translate-hoc.html

或者 d)使用渲染 prop I18n https://react.i18next.com/components/i18n-render-prop.html

jamuhl
2017-09-29

//file.js

import { useTranslation, withTranslation, Trans } from 'react-i18next';

class myClass extends Component{
    //...
    componentDidMount() {
        this.changeLanguage('de'); // en | fr
    }
    changeLanguage = (lng) => {
        const { t , i18n} = this.props;
        i18n.changeLanguage(lng);
    };

    render(){
        //...
    }
}
export default withTranslation()(myClass) // <-- this should solve the issue
Cedric Leo
2021-08-26