Javascript 如何等待流星订阅数据完全完成?
我已经浏览了很多问题/答案以及meteor文档,但在meteor react方面仍然存在问题,并等待订阅数据完全加载。我尝试做两件不同的事情,一件是从数据库接收的数组小于客户端创建的数组,另一件是更大或相等的数组 问题在于我的订阅,数据一次传输一点,所以第一条语句总是至少触发一次 我想知道在调用函数之前,是否有办法确保数据库中的所有数据都已通过Javascript 如何等待流星订阅数据完全完成?,javascript,reactjs,meteor,Javascript,Reactjs,Meteor,我已经浏览了很多问题/答案以及meteor文档,但在meteor react方面仍然存在问题,并等待订阅数据完全加载。我尝试做两件不同的事情,一件是从数据库接收的数组小于客户端创建的数组,另一件是更大或相等的数组 问题在于我的订阅,数据一次传输一点,所以第一条语句总是至少触发一次 我想知道在调用函数之前,是否有办法确保数据库中的所有数据都已通过 if (import.length < arrayLength) { ... } if (import.length >
if (import.length < arrayLength) {
...
}
if (import.length > arrayLength || import.length === arrayLength) {
...
}
if(import.lengtharrayLength | | import.length===arrayLength){
...
}
下面是完整的代码示例
import { DropzoneDialog } from "material-ui-dropzone";
import React, { useState, useEffect, useRef } from "react";
import Button from "@material-ui/core/Button";
import { Cards } from "../../../../both/collections";
import { withTracker } from "meteor/react-meteor-data";
import { makeStyles } from "@material-ui/core/styles";
import { Meteor } from 'meteor/meteor';
import _, { map, object } from 'underscore';
const useStyles = makeStyles({
importButton: {
color: "#C8C8C8",
borderColor: "#C8C8C8",
"&:hover": {
backgroundColor: "rgba(72,72,72,0.7)",
borderColor: "rgba(255, 255, 255)",
color: "rgba(255, 255, 255)",
},
},
});
function importDeck(files, setDeckIsReady, setDeckLength, setCountObj, sub, setSubscription) {
let reader = new FileReader();
reader.readAsText(files[0]);
reader.onload = function () {
let cardArray = reader.result.split("\n");
let cardArrayFiltered = cardArray.filter(Boolean)
const countObj = cardArrayFiltered.reduce((acc, next) => {
count = next.substr(0, next.indexOf(' '));
name = next.substr(next.indexOf(' ') + 1);
return {...acc, [name]: count}
}, {});
sub.stop()
const subscription = Meteor.subscribe('cardSearchTwo', Object.keys(countObj), {onReady() {setDeckIsReady(true)}})
setDeckLength(Object.keys(countObj).length)
setCountObj(countObj)
setSubscription(subscription)
};
}
export function DeckImport({importCards, setCurrentDeck, importDeckFinal, search, setSearch}) {
const classes = useStyles()
const [open, setOpen] = useState(false);
const [deckIsReady, setDeckIsReady] = useState(false);
const [deckLength, setDeckLength] = useState(0);
const [countObj, setCountObj] = useState({});
const [subscription, setSubscription] = useState({stop(){}})
const [isReady, setIsReady] = useState(false)
console.log(deckIsReady, importCards)
let missingCards = []
let fixedDeck = importCards
useEffect(() => {
if (importCards.length < deckLength && deckIsReady) {
fixedDeck = []
Object.keys(countObj).forEach(card => {
if (!importCards.some(e => e.name === card)) missingCards.push(card)
})
fixedDeck = importCards.filter(card => !missingCards.includes(card.name))
console.log('LESS THAN', fixedDeck.length, missingCards.length)
importDeckFinal(fixedDeck, setCurrentDeck, countObj)
setDeckIsReady(false)
setDeckLength(0)
setCountObj({})
}
if ((importCards.length > deckLength || importCards.length === deckLength) && deckIsReady) {
fixedDeck = []
importCards.forEach(card => {
if (card.name in countObj) fixedDeck.push(card)
})
console.log('EQUAL', fixedDeck);
importDeckFinal(fixedDeck, setCurrentDeck, countObj)
setDeckIsReady(false)
setDeckLength(0)
setCountObj({})
}
})
return (
<div>
<Button
variant="outlined"
color="primary"
component="label"
onClick={() => setOpen(true)}
className={classes.importButton}>
Import
</Button>
<DropzoneDialog
acceptedFiles={["text/*"]}
cancelButtonText={"cancel"}
submitButtonText={"submit"}
maxFileSize={5000000}
open={open}
onClose={() => setOpen(false)}
onSave={(files) => {
importDeck(
files,
setDeckIsReady,
setDeckLength,
setCountObj,
subscription,
setSubscription,
setIsReady
);
setOpen(false);
}}
showPreviews={true}
showFileNamesInPreview={true}
/>
</div>
)
}
export default withTracker(props => {
const cards = Cards.find({}, { sort: {name: 1}}).fetch();
const uniqueNames = _.uniq(cards.map(function(x) {return x.name;}), true)
return {
importCards: uniqueNames.map(name => cards.find(({ name: cName }) => cName === name))
};
})(DeckImport);
从“物料ui dropzone”导入{DropzoneDialog};
从“React”导入React,{useState,useffect,useRef};
从“@物料界面/核心/按钮”导入按钮;
从“../../../../both/collections”导入{Cards}”;
从“流星/反应流星数据”导入{withTracker};
从“@material ui/core/styles”导入{makeStyles}”;
从“流星/流星”导入{Meteor};
从“下划线”导入{map,object};
const useStyles=makeStyles({
导入按钮:{
颜色:#C8C8C8”,
边框颜色:“C8C8C8”,
“&:悬停”:{
背景色:“rgba(72,72,72,0.7)”,
边框颜色:“rgba(255,255,255)”,
颜色:“rgba(255,255,255)”,
},
},
});
函数importDeck(文件、setDeckIsReady、setDeckLength、setCountObj、sub、setSubscription){
let reader=new FileReader();
reader.readAsText(文件[0]);
reader.onload=函数(){
让cardArray=reader.result.split(“\n”);
让cardArrayFiltered=cardArray.filter(布尔值)
const countObj=cardArrayFiltered.reduce((acc,next)=>{
count=next.substr(0,next.indexOf(“”));
name=next.substr(next.indexOf(“”)+1);
返回{…acc[name]:count}
}, {});
副主席(译文)
const subscription=Meteor.subscripte('cardSearchTwo',Object.keys(countObj),{onReady(){setDeckIsReady(true)}})
setDeckLength(Object.keys(countObj.length)
setCountObj(countObj)
设置订阅(订阅)
};
}
导出函数DeckImport({importCards,setCurrentDeck,importDeckFinal,search,setSearch}){
常量类=useStyles()
const[open,setOpen]=useState(false);
const[deckIsReady,setDeckIsReady]=使用状态(false);
常数[deckLength,setDeckLength]=使用状态(0);
const[countObj,setCountObj]=useState({});
常量[subscription,setSubscription]=useState({stop(){}})
常量[isReady,setIsReady]=useState(false)
控制台日志(deckIsReady、importCards)
让丢失的卡片=[]
让fixedDeck=importCards
useffect(()=>{
if(importCards.length{
如果(!importCards.some(e=>e.name==card))丢失了cards.push(card)
})
fixedDeck=importCards.filter(卡片=>!missingCards.includes(卡片名称))
console.log('小于',fixedDeck.length,missingCards.length)
importDeckFinal(fixedDeck、setCurrentDeck、countObj)
setDeckIsReady(错误)
setDeckLength(0)
setCountObj({})
}
如果((importCards.length>deckLength | | importCards.length==deckLength)&&deckIsReady){
fixedDeck=[]
importCards.forEach(卡片=>{
if(countObj中的card.name)fixedDeck.push(卡片)
})
console.log('EQUAL',fixedDeck);
importDeckFinal(fixedDeck、setCurrentDeck、countObj)
setDeckIsReady(错误)
setDeckLength(0)
setCountObj({})
}
})
返回(
setOpen(真)}
className={classes.importButton}>
进口
setOpen(false)}
onSave={(文件)=>{
进口检验(
文件夹,
赛德克已经准备好了,
设定长度,
setCountObj,
订阅
设置订阅,
setIsReady
);
setOpen(假);
}}
showPreviews={true}
showFileNamesInPreview={true}
/>
)
}
使用跟踪器导出默认值(道具=>{
const cards=cards.find({},{sort:{name:1}}).fetch();
const uniqueNames=uq.uniq(cards.map(函数(x){return x.name;}),true)
返回{
importCards:uniqueNames.map(name=>cards.find({name:cName}=>cName==name))
};
})(进口);
具体地说,deckIsReady在只有一部分数据真正准备就绪时被设置为True。我更熟悉正常的meteor订阅/发布逻辑,不太清楚您的react逻辑会如何影响事情 有了这句话,
const subscription=Meteor.subscripte('cardSearchTwo',Object.keys(countObj),{onReady(){setDeckIsReady(true)}})
这一行会被多次重新运行,在回调中,您只是设置了甲板准备就绪的期望值,但是,在回调之外,您正在设置组长度和其他与您刚才所做的订阅相关的内容—这意味着这些行将在订阅从发布函数获取数据之前发生
if (import.length < arrayLength) {
...
}
if (import.length > arrayLength || import.length === arrayLength) {
...
}
因此,这里的解决方案是将那些与数据组相关的内容放在回调中,以便正确设置它们,然后在最后通过调用setDeckIsReady(true)
触发反应式DeckImport
,您可以使用两个内容
React钩子,它是流星反应数据的一部分。每当反应式数据源发生更改时,此挂钩将重新运行useTracker
- 使用
Subscription.ready()
const importReady = useTracker(() => Meteor.subscribe('cardSearchTwo').ready())
您可以使用方法从服务器获取数据。逻辑比usin简单