#reactjs #typescript #visual-studio-code #vscode-extensions
#reactjs #typescript #visual-studio-code #vscode-расширения
Вопрос:
Я пытаюсь использовать React внутри панели веб-просмотра vscode. Я бы считал себя приличным компонентом в react, но я привык общаться с серверной частью через http.
В этом проекте расширение vscode по сути является сервером, и вся коммуникация должна осуществляться путем отправки событий между ними.
//vscode extension (server)
//send message to react app
panel.webview.postMessage({ command: 'refactor' });
//receive messages from react app
panel.webview.onDidReceiveMessage(message => console.log(message))
//webview (react app)
//send message to extension
const vscode = acquireVsCodeApi();
vscode.postMessage({command: 'hello', text: 'world'});
//receive messages from extension
window.addEventListener('message', event => console.log(event))
Мой мозг пытается определить наилучший способ настройки двусторонней связи.
Например, выполнение запроса из webview для получения данных для ресурса обычно выглядело бы примерно так:
public refresh = () => {
this.setState({loading: true}, async () => {
try{
const item = await (await fetch('api/items/3')).json();
this.setState({item});
}catch(e){
this.setState({loading: false, err: e});
}
})
}
Но с Event API этот подход, очевидно, не работает…
public refresh = () => {
// could register a listener before sending and deactivate it after, but that seems wrong!
vscode.postMessage({command: 'getItems', id: '3'});
}
Я вижу некоторую дискуссию о регистрации слушателей в componentDidMount
, но поскольку событие является универсальным message
, то практически каждый компонент, который взаимодействует с сервером, будет прослушивать, а затем должен отфильтровывать то, что его волнует.
Одна из идей на этом этапе заключается в создании уровня абстракции, который позволяет отправлять сообщения и ожидать ответа:
//track requests and wait for a response
const PENDING_REQUESTS = {};
function vscodeFetch(payload: any){
return new Promise((resolve, reject) => {
let reqId = crypto.getRandomValues(new Uint32Array(4)).join('-');
vscode.postMessage({reqId, payload);
PENDING_REQUESTS[reqId] = {resolve, reject};
});
}
//handle update resolve/reject promises on response
window.addEventListener('message', event => {
const message = event.data;
if(message.reqId){
let promise = PENDING_REQUESTS[message.reqId];
delete PENDING_REQUESTS[message.reqId];
if(message.success){
p.resolve(message.resp);
}else{
p.reject(message.err);
}
}
});
let items = await vscodeFetch({command: 'getItems', data: {id: 3}});
но такое ощущение, что я бы изобрел свой собственный протокол (звучит просто, пока вы не начнете рассматривать исключительное поведение, такое как тайм-ауты)!
Комментарии:
1. Отошел, чтобы выпить кофе, и это сработало! При такой настройке Redux работал бы великолепно. Иногда требуется написать диссертацию по stackoverflow, чтобы просто обдумать проблему