J'essaie actuellement de faire fonctionner un projet pour tester certaines choses et je suis coincé à un point où j'essaye de mettre à jour l'état correctement.
J'ai un point de terminaison accessible via axios. get ("/ docker / containers") qui renverra un tableau pour tous les ID des conteneurs qui sont actuellement en cours d'exécution sur mon système, ceci se fait comme ceci:
render() {
const containers: any = [];
const curStateOfContainers: IndividualContainer[] = [...this.state.containers];
if (curStateOfContainers.length > 0) {
curStateOfContainers.map(container => {
const container_id = container.id.slice(0, 12);
containers.push(
<Container
key = {container_id}
container_id = {container.id}
name = {container.name}
clickHandler = {() => this.setWatcher(container.id)}
/>
);
});
}
return containers;
}
À ce stade, mon état ressemble à ceci:
updateContainers() {
axios.get('/docker/containers')
.then(response => {
const apiRequestedContainers: string[] = response.data.containers;
// array of only IDs
const stateContainers: IndividualContainer[] = [
...this.state.containers
];
// remove dead containers from state by copying still live containers
let filteredContainers: IndividualContainer[] = [
...this.filterOutContainers(stateContainers, apiRequestedContainers)
];
// add new containers
filteredContainers = this.addContainerToArray(
filteredContainers, apiRequestedContainers
);
return this.updateContainer(filteredContainers);
})
.then(finalArray => {
const newState: CState = {'containers': finalArray};
this.setState(newState);
});
};
updateContainer(containers: IndividualContainer[]) {
const returnArray: IndividualContainer[] = [];
containers.forEach(container => {
if (container.watcher) {
axios.get('/docker/containers/' + container.id)
.then(response => {
// read currently available array of containers into an array
const resp = response.data;
resp['id'] = container.id;
resp['watcher'] = true;
returnArray.push(resp);
});
} else {
returnArray.push(container);
}
return returnArray;
});
};
L'interface utilisateur affiche alors simplement une liste d'identifiants.
Je peux alors cliquer sur un ID sur mon interface utilisateur et il définira un observateur:
TS2322: Type 'void' is not assignable to type 'IndividualContainer[]'.
Le but de l'observateur est que lors du prochain cycle de mise à jour des informations plus détaillées sur un conteneur particulier soient récupérées.
state = {
containers: [{id: 'id1', watcher: false}, {id: 'id2'}]
}
En cliquant sur le conteneur dans l'interface utilisateur où un watcher est déjà défini, alors le watcher est supprimé et le des informations plus détaillées ne sont alors plus récupérées
state = {
containers: [{id: 'id1', watcher: true, name: 'container1'}, {id: 'id2'}]
}
Là où je suis bloqué, c'est comment obtenir des informations plus détaillées rmation. Ma méthode updateContainers comporte 3 étapes:
Lisez la réponse de l'API et détruisez l'état en variables séparées, comparez la var d'état avec la var de réponse et supprimez tous les conteneurs qui sont tombés en panne (aucun setState n'est fait ici) .
Ajoutez tous les nouveaux conteneurs de la réponse à l'état qui sont apparus depuis (encore une fois pas de setState ).
... Tout va bien jusqu'à présent ...
observateur est défini. Où il est défini, effectuez un appel API pour récupérer les informations plus détaillées. Définissez enfin l'état. À l'étape 3, j'utilise un forEach sur le tableau filtré, puis je fais un axios.get ("/ docker / containers / id1") où un watcher a été défini, sinon gardez simplement les détails du conteneur que j'ai déjà mais c'est là que je suis bloqué, Typescript me donne également l'erreur:
state = {
containers: [{id: 'id1', watcher: true}, {id: 'id2'}]
}
J'ai actuellement:
state = {
containers: [{id: 'id1'}, {id: 'id2'}]
}
Tout pointeur vers où ma logique échoue serait apprécié!
Modifier: p >
Méthode de rendu:
componentDidMount() {
this.interval = setInterval(() => this.updateContainers(), 3000);
};
componentWillUnmount() {
clearInterval(this.interval);
}
3 Réponses :
Je ne suis pas un expert en TypeScript, j'ai donc dû changer la réponse en JS et j'ai pensé que vous la réécririez dans TS au cas où cela serait nécessaire.
async updateContainers() {
const response = await axios.get('/docker/containers')
const apiRequestedContainers = response.data.containers; // array of only IDs
const stateContainers = [...this.state.containers];
// remove dead containers from state by copying still live containers
let filteredContainers = [...this.filterOutContainers(stateContainers, apiRequestedContainers)];
// add new containers
filteredContainers = this.addContainerToArray(filteredContainers, apiRequestedContainers);
const containers = await this.updateContainer(filteredContainers)
this.setState({ containers });
};
async updateContainer(containers) {
return containers.map(async (container) => {
if (container.watcher) {
const response = await axios.get('/docker/containers/' + container.id)
// read currently available array of containers into an array
return {
...response.data,
id: container.id,
watcher: true,
}
} else {
return container;
}
});
}
Voici ce que je 'ai mis à jour dans updateContainer:
Merci pour la réponse. Je l'ai implémenté mais j'obtiens une erreur dans la méthode de rendu: Uncaught TypeError: container.id est undefined render Containers.tsx: 138 render Containers.tsx: 137 React 11 unstable_runWithPriority scheduler.development.js: 653 React 6 updateContainers Containers.tsx: 88 Un journal de console de container = await ... montre un tableau de promesses.
J'ai ajouté ma méthode de rendu au message d'origine au cas où cela aiderait
@Oceanic_Panda oui, car ce que vous avez actuellement est une liste de promesses au lieu des informations réelles du conteneur dans le tableau. Pouvez-vous partager le fichier avec nous afin que nous puissions voir directement le problème? L'affichage de morceaux de code avec une erreur de ligne potentielle n'aidera pas à résoudre le problème
Le problème est que vous ne renvoyez rien de la méthode updateContainer qui renverra void implicitement:
// I added a return type here so that TypeScript would yell at me if I return void or wrong type
updateContainer(containers: IndividualContainer[]): IndividualContainer[] {
const returnArray: IndividualContainer[] = [];
containers.forEach(container => {
if (container.watcher) {
axios.get("/docker/containers/" + container.id).then(response => {
// read currently available array of containers into an array
const resp = response.data;
resp["id"] = container.id;
resp["watcher"] = true;
returnArray.push(resp);
});
} else {
returnArray.push(container);
}
// removed the return from here as it's useless
});
// you should return the array here
return returnArray;
}
Ensuite, vous attribuez void à conteneurs qui est censé être de type IndividualContainer [] donc TypeScript vous donne une erreur puis vous définissez cela dans l'état:
updateContainers() {
axios
.get("/docker/containers")
.then(response => {
const apiRequestedContainers: string[] = response.data.containers; // array of only IDs
const stateContainers: IndividualContainer[] = [
...this.state.containers
];
// remove dead containers from state by copying still live containers
let filteredContainers: IndividualContainer[] = [
...this.filterOutContainers(stateContainers, apiRequestedContainers)
];
// add new containers
filteredContainers = this.addContainerToArray(
filteredContainers,
apiRequestedContainers
);
// this return void as well
return this.updateContainer(filteredContainers);
})
// finalArray is void
.then(finalArray => {
// you assign void to containers which should be of type IndividualContainer[]
const newState: CState = { containers: finalArray };
// containers will be set to undefined in you state
this.setState(newState);
});
}
Vous vouliez faire ceci:
// This function return void
updateContainer(containers: IndividualContainer[]) {
const returnArray: IndividualContainer[] = [];
containers.forEach(container => {
if (container.watcher) {
axios.get("/docker/containers/" + container.id).then(response => {
// read currently available array of containers into an array
const resp = response.data;
resp["id"] = container.id;
resp["watcher"] = true;
returnArray.push(resp);
});
} else {
returnArray.push(container);
}
// this is inside the forEach callback function not updateContainer function
return returnArray;
});
}
Je vous en prie. Je suis heureux que cela ait aidé. Si vous avez encore des problèmes, je serais ravi de vous aider.
Premièrement, j'ai commenté les erreurs dans votre code:
const containers = await Promise.all(this.updateContainer(filteredContainers))
Maintenant, pourquoi la réponse de @ RocKhalil fonctionne en quelque sorte:
const containers = await this.updateContainer(filteredContainers)
Merci pour la réponse et le raisonnement inclus!
Veuillez expliquer la méthode
addContainerToArrayDans cette méthode, j'ajoute des conteneurs de mon objet de réponse initial à l'état. Donc dans le cas où un nouveau conteneur est mis en ligne par exemple.
veuillez expliquer cette méthode. Il doit renvoyer un tableau de IndividualContainer
Quelle ligne vous donne l'erreur TS?
Donc, la méthode prend 2 tableaux, le premier tableau est les conteneurs déjà dans l'état de l'application, le second est les conteneurs reçus par la dernière requête get, tous les conteneurs de la requête get qui ne sont pas dans l'état puis sont ajoutés, tous les conteneurs dans les deux les tableaux sont préservés de l'état, cela est dû à la nécessité de conserver le paramètre watcher.
const newState: CState = {'conteneurs': finalArray}; donne l'erreur TS