admin管理员组

文章数量:1299980

I have the following ReactJS ponent:

articles_list.jsx

import React from 'react';
import marked from 'marked';
import './articles_list.css';

export default class ArticlesList extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      articles: null
    }
  }

  ponentWillMount() {
    fetch('/articles_all')
    .then(res => res.json())
    .then(json => {
      this.setState({
        articles: json.articles
      });
    });
  }

  handleClick(e) {
    e.preventDefault();
    var elem = e.target;
    var file = elem.getAttribute('data-file').split('.')[0];
    fetch('/article/'+file, {
      headers: {
        'Accept': 'text/markdown'
      }
    })
    .then(res => res.text())
    .then(txt => marked(txt))
    .then(html => document.getElementById('article-text').innerHTML = html)
  }

  render() {

    var teste = []

    if (this.state.articles === null) {
      teste.push(<div id="no-articles" key="1">No articles</div>)
    } else {
      {this.state.articles.forEach( function(element, index) {
        teste.push(<div onClick={this.handleClick} data-file={element.file} className="articles-menu-item" key={index.toString()}>{element.title}</div>);
      }.bind(this))}
    }

    return(
      <div className="articles-list">
        <div className="articles-list-title">
          ARTICLES
        </div>
        <div id="menu-body" className="menu-body">{teste}</div>
      </div>
    );
  }
}

As you may see, it fetches as list of articles and creates links. When these links are clicked the corresponding article is load in a certain area of the page.

The code is working perfectly, but now I need to load a certain article before any of the links to be clicked. Then I decided to break the code inside handleClick like this:

   loadArticle(file) {
     fetch('/article/'+file, {
       headers: {
         'Accept': 'text/markdown'
       }
     })
     .then(res => res.text())
     .then(txt => marked(txt))
     .then(html => document.getElementById('article-text').innerHTML = html)
   }

   handleClick(e) {
    e.preventDefault();
    var elem = e.target;
    var file = elem.getAttribute('data-file').split('.')[0];
    loadArticle(file);
  }

My idea with this is to invoke loadArticle inside render to load an specific article when the ponent loads, like this:

return(
  <div className="articles-list">
    <div className="articles-list-title">
      ARTICLES
    </div>
    <div id="menu-body" className="menu-body">{teste}{this.loadArticle('my_specific_article')}</div>
  </div>
);

It works and now my_specific_article loads correctly when I navigate to the page. But...

But now when I click the links, that were working fine before, I got an error

Uncaught ReferenceError: loadArticle is not defined

And if I do

   handleClick(e) {
    e.preventDefault();
    var elem = e.target;
    var file = elem.getAttribute('data-file').split('.')[0];
    this.loadArticle(file);
  }

using this, then I get

Uncaught TypeError: Cannot read property 'loadArticle' of null

How should I deal with this? I know it is a matter of context but, being new to ReactJS, I really don't know how to proceed.

EDIT

This is not a duplicate of this question, as it was marked. The reason is simple. In the mentioned question the function to bind is a event handler and in my problem a function being called by another. In fact, my event handler (similar to the other question) was working fine without the bind, then we are not talking about the same thing.

I have the following ReactJS ponent:

articles_list.jsx

import React from 'react';
import marked from 'marked';
import './articles_list.css';

export default class ArticlesList extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      articles: null
    }
  }

  ponentWillMount() {
    fetch('/articles_all')
    .then(res => res.json())
    .then(json => {
      this.setState({
        articles: json.articles
      });
    });
  }

  handleClick(e) {
    e.preventDefault();
    var elem = e.target;
    var file = elem.getAttribute('data-file').split('.')[0];
    fetch('/article/'+file, {
      headers: {
        'Accept': 'text/markdown'
      }
    })
    .then(res => res.text())
    .then(txt => marked(txt))
    .then(html => document.getElementById('article-text').innerHTML = html)
  }

  render() {

    var teste = []

    if (this.state.articles === null) {
      teste.push(<div id="no-articles" key="1">No articles</div>)
    } else {
      {this.state.articles.forEach( function(element, index) {
        teste.push(<div onClick={this.handleClick} data-file={element.file} className="articles-menu-item" key={index.toString()}>{element.title}</div>);
      }.bind(this))}
    }

    return(
      <div className="articles-list">
        <div className="articles-list-title">
          ARTICLES
        </div>
        <div id="menu-body" className="menu-body">{teste}</div>
      </div>
    );
  }
}

As you may see, it fetches as list of articles and creates links. When these links are clicked the corresponding article is load in a certain area of the page.

The code is working perfectly, but now I need to load a certain article before any of the links to be clicked. Then I decided to break the code inside handleClick like this:

   loadArticle(file) {
     fetch('/article/'+file, {
       headers: {
         'Accept': 'text/markdown'
       }
     })
     .then(res => res.text())
     .then(txt => marked(txt))
     .then(html => document.getElementById('article-text').innerHTML = html)
   }

   handleClick(e) {
    e.preventDefault();
    var elem = e.target;
    var file = elem.getAttribute('data-file').split('.')[0];
    loadArticle(file);
  }

My idea with this is to invoke loadArticle inside render to load an specific article when the ponent loads, like this:

return(
  <div className="articles-list">
    <div className="articles-list-title">
      ARTICLES
    </div>
    <div id="menu-body" className="menu-body">{teste}{this.loadArticle('my_specific_article')}</div>
  </div>
);

It works and now my_specific_article loads correctly when I navigate to the page. But...

But now when I click the links, that were working fine before, I got an error

Uncaught ReferenceError: loadArticle is not defined

And if I do

   handleClick(e) {
    e.preventDefault();
    var elem = e.target;
    var file = elem.getAttribute('data-file').split('.')[0];
    this.loadArticle(file);
  }

using this, then I get

Uncaught TypeError: Cannot read property 'loadArticle' of null

How should I deal with this? I know it is a matter of context but, being new to ReactJS, I really don't know how to proceed.

EDIT

This is not a duplicate of this question, as it was marked. The reason is simple. In the mentioned question the function to bind is a event handler and in my problem a function being called by another. In fact, my event handler (similar to the other question) was working fine without the bind, then we are not talking about the same thing.

Share Improve this question edited Jun 7, 2017 at 8:19 Edvaldo Silva de Almeida Jr asked Jun 7, 2017 at 7:47 Edvaldo Silva de Almeida JrEdvaldo Silva de Almeida Jr 3,7235 gold badges30 silver badges61 bronze badges 5
  • binding issue, write this line in the constructor: this.handleClick = this.handleClick.bind(this) or convert that function into arrow, like this: handleClick = (e) => { – Mayank Shukla Commented Jun 7, 2017 at 7:52
  • Possible duplicate of Reactjs ponent does not re-render after setState – Shubham Khatri Commented Jun 7, 2017 at 8:12
  • The issue is the same, this is not referering to the correct context, there are a lots of questions having the same issue, The first I found, I added – Shubham Khatri Commented Jun 7, 2017 at 8:23
  • I understand your point, thanks @ShubhamKhatri. – Edvaldo Silva de Almeida Jr Commented Jun 7, 2017 at 8:30
  • No Problem :), Any ways glad your problem was solved – Shubham Khatri Commented Jun 7, 2017 at 8:31
Add a ment  | 

1 Answer 1

Reset to default 5

You must bind your custom functions in the constructor. Modify your constructor like this.

constructor(props) {
  super(props);
  this.state = {
    articles: null
  }
 this.handleClick = this.handleClick.bind(this);
 this.loadArticle = this.loadArticle.bind(this);
}

Now everywhere you should call this function as this.handleClick & this.loadMore.

You can read about other binding patterns here. The one I've mentioned is number 4.

That is the preferred way in facebook docs as well.

本文标签: javascriptCalling a function from another in ReactJsStack Overflow