Javascript React JS:通过另一个对象数组过滤一个对象数组。如何顺序执行四个函数,包括几个API调用

Javascript React JS:通过另一个对象数组过滤一个对象数组。如何顺序执行四个函数,包括几个API调用,javascript,arrays,reactjs,filtering,sequential,Javascript,Arrays,Reactjs,Filtering,Sequential,目标是通过另一个对象数组过滤一个对象数组。 每个阵列来自不同的源 下面的设置可能看起来很奇怪,但出于一些未提及的原因,很不幸,这是必要的 第一步是从Firebase数据库获取一个对象数组,其中包含一些(最新)上传帖子(allposts)的元数据 在第二步中,将针对userid和textids(FilterArrayId)对该数组进行过滤 在第三步中,将为每个过滤后的用户标识调用一个API,以获取对应用户标识的所有现有帖子的详细信息。这些将合并到一个POST数组(fetchJSONFiles)中

目标是通过另一个对象数组过滤一个对象数组。 每个阵列来自不同的源

下面的设置可能看起来很奇怪,但出于一些未提及的原因,很不幸,这是必要的

  • 第一步是从Firebase数据库获取一个对象数组,其中包含一些(最新)上传帖子(allposts)的元数据
  • 在第二步中,将针对userid和textids(FilterArrayId)对该数组进行过滤
  • 在第三步中,将为每个过滤后的用户标识调用一个API,以获取对应用户标识的所有现有帖子的详细信息。这些将合并到一个POST数组(fetchJSONFiles)中
  • 在第四步中,应该为第二步的textids数组(filterJSON)中的所有textids过滤合并后的post数组
以下是我目前的解决方案。不幸的是,我无法按顺序执行函数,因此在调用filterJSON()之前,fetchJSONfiles()已完全完成

我被困在这里好几个小时了。。。非常感谢您的任何帮助,这将是我的荣幸。谢谢

示例数据:

allposts: [
  {
    dateofpost: "1539181118111",
    textid: "1",
    userid: "Alice",
  },
  {
    dateofpost: "1539181118222",
    textid: "3",
    userid: "Bob",
  },
]
-

预期成果:

latestPosts: [
  {
    title: "Lorem",
    textid: "1",
  },
  {
    title: "Dolor",
    textid: "3",
  },
]
到目前为止,我的解决方案是:

class Explore extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      allposts: [],
      textids: [],
      userids: [],
      allfilteredTexts: [],
    };
  }

  componentDidMount() {
    const allfilteredTexts = {...this.state.allfilteredTexts}
    firebase
      .firestore()
      .collection("allposts")
      .orderBy("dateofpost")
      .get()
      .then(snapshot => {
        const allposts = this.state.allposts;
        snapshot.forEach(doc => {
          allposts.push({
              userid: doc.data().userid,
              textid: doc.data().textid,
              dateofpost: doc.data().dateofpost,
          });
        });

        this.setState({
          allposts: allposts,
        });
      })
      .catch(function(error) {
        console.log("Error getting documents: ", error);
      })
      .then(() => {
              this.filterArrayIds();
      })
      .then(() => {
              this.fetchJSONFiles();
      })
      .finally(() => {
              this.filterJSON();
      });

    }


    filterArrayIds() {
      var userids = this.state.userids
      var textids = this.state.textids
      if (this.state.allposts) {
        var filtereduserids = [...new Set([].concat(...this.state.allposts.map(o => o.userid)))];
        var filteredtextids = [...new Set([].concat(...this.state.allposts.map(p => p.textid)))];
        this.setState({
            userids: filtereduserids,
            textids: filteredtextids,
        })
      }
    }

    fetchJSONFiles() {
      if (this.state.userids) {
         this.state.userids.forEach((username) => {
            var filteredTexts = []
            const options = {username} //here would be more API options //
            getFile(options)
              .then((file) => {
                filteredTexts = JSON.parse(file || '[]');
              })
              .then (() => {
                Array.prototype.push.apply(filteredTexts, this.state.allfilteredTexts);
                this.setState({
                  allfilteredTexts: filteredTexts,  
              })
          })
      }
    }

    filterJSON(){
          let latestPosts = (this.state.allfilteredTexts.filter(
            (el) => { return el.id.indexOf(this.state.textids) !== -1;
            }));
    }

    render () {

      return (
        <div>
              <Switch>
                <Route
                  path='/explore/latest/'
                  render={(props) => <ExploreLatest {...props} allposts={this.state.allposts} allfilteredTexts={this.state.allfilteredTexts} />}
                />
              </Switch>
        </div>
      )
    }
}
export default Explore;
class.Component{
建造师(道具){
超级(道具);
此.state={
所有职位:[],
textId:[],
用户标识:[],
所有FilteredText:[],
};
}
componentDidMount(){
常量allfilteredTexts={…this.state.allfilteredTexts}
火基
.firestore()
.收集(“所有邮件”)
.orderBy(“邮政日期”)
.get()
。然后(快照=>{
const allposts=this.state.allposts;
snapshot.forEach(doc=>{
推({
userid:doc.data().userid,
textid:doc.data().textid,
dateofpost:doc.data().dateofpost,
});
});
这是我的国家({
所有帖子:所有帖子,
});
})
.catch(函数(错误){
log(“获取文档时出错:”,错误);
})
.然后(()=>{
这个.filterArrayIds();
})
.然后(()=>{
this.fetchJSONFiles();
})
.最后(()=>{
this.filterJSON();
});
}
filterArrayIds(){
var userids=this.state.userids
var textids=this.state.textids
if(this.state.allposts){
var filteredUserId=[…新集合([].concat(…this.state.allposts.map(o=>o.userid)))];
var filteredtextids=[…新集合([].concat(…this.state.allposts.map(p=>p.textid)))];
这是我的国家({
用户ID:FilteredUserID,
textids:filteredtextids,
})
}
}
fetchJSONFiles(){
if(this.state.userids){
this.state.userids.forEach((用户名)=>{
var filteredTexts=[]
const options={username}//这里有更多的API选项//
getFile(选项)
。然后((文件)=>{
filteredTexts=JSON.parse(文件| |'[]);
})
.然后(()=>{
Array.prototype.push.apply(filteredTexts,this.state.allfilteredTexts);
这是我的国家({
allfilteredTexts:filteredTexts,
})
})
}
}
filterJSON(){
让latestPosts=(this.state.allfilteredTexts.filter(
(el)=>{返回el.id.indexOf(this.state.textids)!=-1;
}));
}
渲染(){
返回(
}
/>
)
}
}
导出默认值;

我建议这样修改:

fetchJSONFiles() {
      if (this.state.userids) {
         return Promise.all(this.state.userids.map((username) => {
            var filteredTexts = []
            const options = {username} //here would be more API options //
            return getFile(options)
              .then((file) => {
                filteredTexts = JSON.parse(file || '[]');
              })
              .then (() => {
                Array.prototype.push.apply(filteredTexts, this.state.allfilteredTexts);
                this.setState({
                  allfilteredTexts: filteredTexts,  
              })
          }))
      }
    }
那么接下来的台词是:

 .then(() => {
          this.fetchJSONFiles();
  })
可以成为:

 .then(() => {
          return this.fetchJSONFiles();
  })
为什么?

fetchJSONFiles
之所以没有在承诺链的其余部分之前完成,是因为承诺链不知道等待
fetchJSONFiles
fetchJSONFiles
进行异步调用的结果,因此同步代码的其余部分会继续执行

但是,通过从fetchJSONFiles返回承诺,我们可以“等待”。这使用了功能
Promise.all
,基本上是说“创建一个承诺,当此承诺数组中的每个承诺都完成时,该承诺就会完成”

我们使用
map
,而不是
forEach
,因为这允许我们基于基本数组创建一个新数组,而不是在它上面循环。然后,我们返回承诺链,而不是调用
getFile
。因此,我们从
this.state.userids
创建一个承诺数组,并从当使用
Promise.all完成所有回迁时,将在此处解析

然后,我们在位于
componentDidMount
中的初始承诺链中返回该值。这告诉该链等待该承诺的结果(该承诺是
This.fetchJSONFiles
的结果)完成,然后再继续,在这种情况下,这将涉及执行
最终的
回调


现在,还有一些其他的考虑因素要考虑。也就是说,如果在<代码>一个FETCHJSONFrase

.catch(function(error) {
    console.log("Error getting documents: ", error);
  })
  .then(() => {
          this.filterArrayIds();
  })
  .then(() => {
          this.fetchJSONFiles();
  })
  .finally(() => {
          this.filterJSON();
  });
第一个承诺解析时会调用第一个.then(),第二个、第三个和.finally()也会调用第二个、第三个和.finally()

您需要执行以下操作:

firebase
  .get()
  .then(snapshot => {
    // stuff happening with snapshot
    this.filterArrayIds().then(() => {
      this.fetchJSONFiles().then(() => {
        this.filterJSON();
      });
    });
  });

您的方法filterArraysId(),fetchJSONFiles()必须返回一个承诺,当它们完成工作时,该承诺将得到解决;)

非常感谢!特别是对于解释者
firebase
  .get()
  .then(snapshot => {
    // stuff happening with snapshot
    this.filterArrayIds().then(() => {
      this.fetchJSONFiles().then(() => {
        this.filterJSON();
      });
    });
  });