简体   繁体   中英

Javascript JSON.stringify returns []

I am working with ReactJS and need to create an array to insert data, store it in localStorage, and view it later. I first create the array using this.subscriptionsList = []; I then use this method to retrieve the data.

  fetchNow = async (token, nextToken) => {
      fetch("somewebsite")
        .then(( unformattedData ) => {
          return unformattedData.json();
        })
        .then(( webData) => {
          for(let i = 0; i < webData.length; i++){
            this.subscriptionsList.push("someData");
          }
          if(webData.hasOwnProperty('token')){
            this.fetchNow(token, webData.token);
          }else{
            return;
          }
        })
      }

The function is not complete as it is not the focal point of my question. It works fine and pushes the correct data.

I retrieve the data using this method:

this.fetchNow(response.accessToken, "")
      .then( () => {
        console.log(this.subscriptionsList);
        console.log(JSON.stringify(this.subscriptionsList));
        localStorage.setItem("subscriptionsList", JSON.stringify(this.subscriptionsList));
        //console.log(JSON.parse(localStorage.getItem("subscriptionsList")));
      })

The problem appears when I try to use JSON.stringify . Doing console.log(this.subscriptionsList) prints an array object with all the data inside of it as expected. However when I go to do console.log(JSON.stringify(this.subscriptionsList)) it returns [] . Further, when printing the object itself, the property length: 125 but when doing console.log(this.subscriptionsList.length) it returns 0 and when accessing using this.subscriptionsList[0] it returns undefined . I was reading the specifications and it appears as though JSON.stringify should work with a javascript array. Am I missing something react specific or is this just not available with JSON.parse?

https://gyazo.com/72aafe248ef61649a38c06d03fb3d830
https://gyazo.com/c2690b4392774fe4a98254a4d15f3a32
https://gyazo.com/e0793b5ec05da4259e16100f275da414

You need to return the promise chain in fetchNow or you can't chain to it later as you're trying. You'll also have to return the recursive fetchNow called inside fetchNow if you want it to be chained as well:

fetchNow = (token, nextToken) => {
  return fetch("somewebsite")
    .then(( unformattedData ) => {
    return unformattedData.json();
  })
    .then(( webData) => {
    for(let i = 0; i < webData.length; i++){
      this.subscriptionsList.push("someData");
    }
    if(webData.hasOwnProperty('token')){
      return this.fetchNow(token, webData.token);
    }
  })
}

async functions do not magically make asynchronous operations synchronous. They (1) return Promises and (2) allow for the await keyword. But since you're not using await , there's no need for fetchNow to be async , and since the fetch chain is already a Promise , you can return it directly without async .

If you do want to use async and await , it would make the code much flatter and easier to understand:

fetchNow = async (token, nextToken) => {
  const response = await fetch("somewebsite");
  const webData = await response.json();
  for(let i = 0; i < webData.length; i++){
    this.subscriptionsList.push("someData");
  }
  if(webData.hasOwnProperty('token')){
    await this.fetchNow(token, webData.token);
  }
  // async function will automatically return a Promise that resolves when the end is reached
}

This is what's happening.... What console.log(JSON.stringify(something)) does is that it serialises the immediate value and prints the serialised reference.(in other words it creates a cloned copy and prints the cloned copy not the original reference it won't wait for hoisted/mutated value). What console.log(something) does is that it refers to the original value and prints the actual result(mutated/hoisted) rather the immediate result. As your method being an asynchronous one you can clearly observe this. You can wait until the asyc call is done then you can push the actual variable to the localStorage. (Note that even local storage stores as serialised values)

Edit 1:-

let onComplete = (subscriptionsList) => {
    console.log(JSON.stringify(subscriptionsList));
    localStorage.setItem("subscriptionsList", JSON.stringify(subscriptionsList));
    //console.log(JSON.parse(localStorage.getItem("subscriptionsList")));
}

fetchNow = async (token, nextToken, onComplete) => {
  fetch("somewebsite")
    .then(( unformattedData ) => {
      return unformattedData.json();
    })
    .then(( webData) => {
      for(let i = 0; i < webData.length; i++){
        this.subscriptionsList.push("someData");
      }
      if(webData.hasOwnProperty('token')){
        this.fetchNow(token, webData.token);
      }else{
        onComplete(this.subscriptionsList);
        return;
      }
    })
}

this.fetchNow(response.accessToken, "", onComplete)
  .then( () => {
    console.log("direct call ", this.subscriptionsList);
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM