1

I need to start from the very beginning to summarize my problem:

I'm creating a structure with a react framework to build a simple reactive page. I guess I can define it as a single page application:

Here's the structure:

enter image description here

Right now my article-content.js file has the following code:

import $ from "jquery";
const rootURL = 'mytargetwebsite';

const config = {
    rootURL: rootURL,
    taskRoute: `${rootURL}/wp-json/wp/v2/posts`,
};


let articles = '';
let the_request = $.ajax({
    type: 'GET',
    url: config.taskRoute,
    async: false,
});

the_request.done(function(data){

    articles = data.map(data => (

    {
        name: data.title.rendered,
        title: data.link,
        excerpt: data.excerpt.rendered,
        content: data.content.rendered
    }

    ));

});
export default articles;

And it works fine but ideally, this is not how I want to run my app, because my goal is to use a promise or the fetch API to export the variable and reuse it in another file, which is the following:

ArticlesList.js:

import React from 'react';
import { Link } from 'react-router-dom';

const ArticlesList = ({ articles }) => (
    <>
    {articles.map((article, key) => (
        <Link className="article-list-item" key={key} to={`/article/${article.name}`}>
            <h3>{article.title}</h3>
            <h3>{article.name}</h3>
            {/*<div>{article.content}</div>*/}
            <div
            dangerouslySetInnerHTML={{
                __html: article.content
            }}></div>
        </Link>
    ))}
    </>
);

export default ArticlesList;

So, I tried to use the fetch API several times, but I'm not able to export it because, when I try to run the .map function on the ArticlesList.js page an error will be thrown.

Something like:

const ciao = async () => { 
    function fetchDemo() {
        return fetch(config.taskRoute).then(function(response) {
            return response.json();
        }).then(function(json) {
            let articles = json.map(data => (
            {
                name: data.title.rendered,
                title: data.link,
                content: data.content.rendered
            }
            ));
            return articles;

        });
    }
}
const articles = ciao();
console.log(articles);

will never work for some reason but, on the other hand, the idea will work, so the articles will log a promise that it is resolved and contains the data that I need to map or loop through that I need on the other page.

The approach with the promise is very similar and, like in the other case, will work:

const articles = new Promise((resolve,reject) => {
    fetch(config.taskRoute, {
        method: 'GET',
        headers: { 'Content-Type': 'application/json', },
    })
    .then(response => response.json())
    .then(data => {
        resolve(data.map(data => ({
            name: data.title.rendered,
            title: data.link,
            content: data.content.rendered
        })));
    })
    .catch((error) => {
        reject(error)
    });
});

export default articles;

But still, I won't be able to export my variable because it will fail in the other file (ArticlesList.js).

I tried several other approaches but they all fail so far.

Any hint?

UPDATE:

There must be something that I can't know because in theory, my code works fine:

ArticlesList.js

import React from 'react';
import { Link } from 'react-router-dom';
import articles from "../pages/article-content";

articles.then(articles => {
    console.log(articles);
    return;

});

If I console.log articles, it contains the value that I need to map but as soon as I try to map them:

console.log(articles);//works!
const ArticlesList = ({ articles }) => (
    <>
    {articles.map((article, key) => (
        <Link className="article-list-item" key={key} to={`/article/${article.name}`}>
            <h3>{article.title}</h3>
            <h3>{article.name}</h3>
            {/*<div>{article.content}</div>*/}
            <div
            dangerouslySetInnerHTML={{
                __html: article.content
            }}></div>
        </Link>
    ))}
    </>
);//doesn't work

I will get a:

TypeError: articles.map is not a function
Porcellino80
  • 447
  • 7
  • 32

2 Answers2

1

Rather than trying to export articles (which is not possible for many reasons) why not simply export a promise which resolves with articles?

const rootURL = 'mywebsite';

const config = {
    rootURL: rootURL,
    taskRoute: `${rootURL}/wp-json/wp/v2/posts`,
}

const articles = new Promise((resolve,reject) => {
    fetch(config.taskRoute, {
        method: 'GET',
        headers: { 'Content-Type': 'application/json', },
    })
    .then(response => response.json())
    .then(data => {
        resolve(data.map(data => ({
            name: data.title.rendered,
            title: data.link,
            content: data.content.rendered
        })));
    })
    .catch((error) => {
        reject(error)
    });
});

export default articles;

In the importing file

import articles from "./articles";

articles.then(articlesArray => {
    // Here articlesArray is an array and it must be used in this function
});

// Here aritclesArray is not defined

Note this approach works only if you need to load articles at boot time, if you need to load again articles later in your app, it's better to export a function which return a Promise rather than exporting the Promise itself.

Daniele Ricci
  • 15,422
  • 1
  • 27
  • 55
  • I changed my question, your approach is my favorite one, and as I explained in the post, it will work, I will be able to export my variable, but it won't work in the other file. So probably I wasn't able to export it, I'm not 100% sure why it failed – Porcellino80 Jun 07 '20 at 15:46
  • What do you mean "it won't work in the other file"? Probably you need to keep in mind that in other file you have a Promise, so you have to use `.then()` on it – Daniele Ricci Jun 07 '20 at 15:50
  • TypeError: articles.map is not a function ArticlesList src/components/ArticlesList.js:31 28 | }); 29 | console.log(articles); 30 | > 31 | const ArticlesList = ({ articles }) => ( – Porcellino80 Jun 07 '20 at 15:53
  • Sure! As I said the `articles` variable you import is not an array but a promise which resolves with the array. – Daniele Ricci Jun 07 '20 at 15:54
  • let's say that I will export the variable with another name: const something = new Promise((resolve,reject) => { }); export default something; Now, in the other file, how can I use then? Something like: const article = bau.something() ? – Porcellino80 Jun 07 '20 at 15:56
  • I still have this very problem: articles.then(articles => { console.log(articles); return; }); Articles is the variable that I need but I can't use it because: TypeError: articles.map is not a function – Porcellino80 Jun 07 '20 at 16:09
  • The problem must be somewhere here: articles.then(articles => { return; }); console.log(articles); const ArticlesList = ({ articles }) => ( <> {articles.map((article, key) => (

    {article.title}

    {article.name}

    {/*
    {article.content}
    */}
    ))} > ); export default ArticlesList;
    – Porcellino80 Jun 07 '20 at 16:20
  • That's the same problem that I had in my first approach. I'm sure it works but: articles.then(articles => { console.log(articles); const ArticlesList = ({ articles }) => ( <> I can't export export default ArticlesList because Parsing error: 'import' and 'export' may only appear at the top level – Porcellino80 Jun 07 '20 at 17:26
  • You can't export the result of an async function, you can only export something that asynchronously do something and where you import that, you have to use it in an async way – Daniele Ricci Jun 07 '20 at 17:30
  • OK, so how to? That's a really complex logic, I've been working on this problem since Friday, that's the reason why I set a bounty on the answer – Porcellino80 Jun 07 '20 at 17:36
  • I even try something like that: export articles.then(articles => {} But it didn't work – Porcellino80 Jun 07 '20 at 17:37
  • 1
    Can you please tell me how do you need to use articles, @MarcoMaffei ? I'll try to show you an example – Daniele Ricci Jun 07 '20 at 20:37
  • Sure, I create a repository where you can have a look at the app: https://github.com/orso081980/Simple-React-Application/blob/master/react-wordpress-app/myblog/src/pages/article-content.js That's the file, where the original ajax call is in jQuery (sync) – Porcellino80 Jun 07 '20 at 21:28
  • That's instead the other file that I indicated in my thread: https://github.com/orso081980/Simple-React-Application/blob/master/react-wordpress-app/myblog/src/components/ArticlesList.js – Porcellino80 Jun 07 '20 at 21:30
1

Instead of exporting the articles you should export a function that fetches articles and then take care of all the async-await's or promises to resolve the function in the respective component that you use the function in

const rootURL = 'mywebsite.xyz/';

const config = {
    rootURL: rootURL,
    taskRoute: `${rootURL}/wp-json/wp/v2/posts`,
};

const getPeopleInSpace = () => 
    return fetch(config.taskRoute) 
       .then(res => res.json());

const getArticles = () => 
    getPeopleInSpace()
    .then(json => {
        const article = json.map(data => {
            return {
            name: data.title.rendered,
                title: data.link,
                content: data.content.rendered
            }
        });
        return article;
    })

export default getArticles ;

Now you can use the above function in any component like

import getArticles from 'path/to/getArticles';

class App extends React.Component {
   ...
   componentDidMount() {
       getArticles().then(articles => {
          console.log(articles);
          // set articles in state and use them
       }) 
   }
}

One reason why you shouldn't be exporting articles fetched from an API is because everytime you import the file, a new request goes, but you are never guranteed when the request is complete and your items are available to be used. By exporting the function you can handle the success and error scenarios

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • I changed my question, so the topic would be more clear in order to answer. I found your approach in several articles, but for some reason, I wasn't able to export or reuse my variable. – Porcellino80 Jun 07 '20 at 15:48
  • @MarcoMaffei you don't use the variable, you use the function. I did show you an example too – Shubham Khatri Jun 07 '20 at 15:49