Figma React plugin PostMessage not working as expected - reactjs

I'm trying to create a plugin for Figma, which has been going fine until now. It's based on the react example they provide on their github page: https://github.com/figma/plugin-samples/tree/master/react
In this example I've created a button, that on click will call this function:
(file: ui.tsx)
onClick = () => {
parent.postMessage({pluginMessage: {type: 'GetData'}}, '*');
};
This is parent.postMessage is a function figma provides to communicate with another file in the project, code.ts. This file will receive the postMessage with the pluginMessage as parameter, which works as expected. The code.ts that receives this looks like this:
(file: code.ts)
figma.ui.onmessage = msg => {
if (msg.type === 'GetData') {
figma.ui.postMessage({"title": figma.currentPage.selection[0].name});
}
};
This file receives the message, and it gets in the if statement since GetData has been set. Up until here, everything is good and well. The issue I'm walking into is the figma.ui.postMessage({}), which should do a callback to the onmessage function in ui.tsx:
(file: ui.tsx)
onmessage = (selection) => {
console.log(selection);
};
This onmessage function should, according to Figma's documentation, receive the object from the postMessage in code.ts. This does however never happen; it will never be called at all. I can't access the current selection in ui.tsx, so I need data from code.ts. Is there any way to pass this data to ui.tsx, or does anyone know why this doesn't work?

I encountered the same issue. Within your ui.tsx file, try adding the following:
window.onmessage = selection => {
let message = selection.data.pluginMessage;
console.log(message);
}

or try this ->
window.addEventListener("message", (selection) => {
console.log(selection);
});
this will add another message event handler to the window. if you use onmessage it might overwrite the previous handler!

put first of script
onmessage = event => {
console.log("got this from the plugin code", event, event.data.pluginMessage)
}

Related

CHROME -EXTENSIONS: How can I run message passing multiple times?

I am working on a project which produces a Chrome extension. In a background page I have a function named checkingProcess. This function is executed when a new tab is opened or a tab is updated. (I tried to catch the change of URL here.)
chrome.tabs.onActivated.addListener((activeInfo) => {
checkingProcess(activeInfo.tabId)
})
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
checkingProcess(tab.id)
})
Then, in the checkingProcess function, I have some functions for the data handling and API calls. Then I tried to receive a message that comes from popup. This message represents that the popup was opened by the user.
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.msg === 'popup_opened') {
sendResponse({
matches_length: response['matches'].length,
hostname: host,
})
}
chrome.runtime.lastError
})
After that, it sends a response to the popup. In the popup, I listen to the message and use the response in the popup.
useEffect(() => {
chrome.runtime.sendMessage({ msg: 'popup_opened' }, (res) => {
setHostname(res['hostname'])
setMatchesLength(res['matches_length'])
console.log(res['hostname'], 'burası')
console.log(res['matches_length'], 'burası')
})
}, [])
However, I realize that this message process is only executed once, but I need to run it multiple times to access the data in background simultaneously. How can I do that?
Your message is only sent once because it's currently setup in a React.useEffect with an empty list of dependencies. This means this code will only be run once when your component is mounted. If you want to run it "multiple times" you first need to define what this means? Examples are:
Executing sendMessage after a user performs some action, like clicking a button. In that case you don't need useEffect. Instead, wire an event handler to that button and perform the sendMessage there.
Executing sendMessage after re-render of your component. Simply remove the empty list of dependencies ([]) from your useEffect method. Note: use this with caution. If you setup your component in a way that it re-renders often, this can quickly turn into a situation where many API calls are made.
Executing sendMessage after some state within your component changes. Add this variable to the list of dependencies: [loaded]
Executing sendMessage every 10 seconds. You'll want to use setInterval within your useEffect, like this:
useEffect(() => {
const interval = setInterval(() => {
chrome.runtime.sendMessage({ msg: 'popup_opened' }, (res) => {
setHostname(res['hostname'])
setMatchesLength(res['matches_length'])
console.log(res['hostname'], 'burası')
console.log(res['matches_length'], 'burası')
})
}, 10000);
return () => clearInterval(interval);
}, []);

What is the correct way to stop receiving streaming updates from an RTKQ?

I tried to call an unsubscribe function:
unsubscribeFromThingIds(arg.tids);
after the await cacheEntryRemoved; line in this example.
The function is defined like this:
export const unsubscribeFromThingIds = (tids: string[]) => {
followedThingIds = followedThingIds.filter(
id => !tids.includes(id)
);
const argument = { tids: followedThingIds } as ITimersChannelInitParams;
myIo!.emit("configure timers channel", argument);
};
(where myIo is the Socket.IO client)
This is not working currently for me. I am currently debugging this issue.
I also tried to use an useEffect hook with a returned cleanup function for running it when the component unmounts, something like this:
useEffect(() => {
return () => {
unsubscribeFromThingIds(getTimersQueryParams.tids);
};
}, [getTimersQueryParams]);
I want to ask for this information because I am not sure which one of the two ideas should I work on more, or if there is another thing I can do that is better.
Could it be that you are just impatient? The cache entry will be removed 60 seconds (the keepUnusedDataFor option) after the last component stops using it.
Generally: using the endpoint lifecycle and awaiting cacheEntryRemoved is the right way to do this if you started the listener within onCacheEntryAdded. If you want it to happen earlier, just use a shorter keepUnusedDataFor duration.

Unable to set up invisible reCAPTCHA verifier for multi-factor authentication in a react app

As per this article, https://cloud.google.com/identity-platform/docs/web/mfa, I am trying to set up invisible reCAPTCHA. However, the callback function does not seem to fire. The idea is that I want the recaptcha to fire off upon a button click and send a code via the callback function but it is not working.
I am trying to activate the recaptcha via the following function linked to a button with the 'code-button" id.
sendCode () {
const recaptchaVerifier = new firebase.auth.RecaptchaVerifier('code-button', {
'size': 'invisible',
'callback': () => {
// reCAPTCHA solved, you can proceed with phoneAuthProvider.verifyPhoneNumber(...).
// onSolvedRecaptcha();
console.log("captcha is working")
}
})
recaptchaVerifier.render()
}
When I press the button to fire off the sendCode function, the callback inside the recaptchaVerifier does not seem to work. It is supposed to console.log "captcha working" but it does not as I check the console.
I do get the following issues in the console but I am not sure if they are actually blocking the callback or making the recaptcha not work:
Indicate whether to send a cookie in a cross-site request by specifying its SameSite attribute
SharedArrayBuffer usage is restricted to cross-origin isolated sites
I do not even know how to resolve them. As per some articles, they seem to be issues that can only be resolved by Google itself.
Does anyone know why this is happening?
Thanks.
I solved this issue myself by dropping the callback from within and instead I simply called recaptchaVerifier from another function as needed. For example:
First, initialize the recaptcha and render it:
const recaptchaVerifier = new firebase.auth.RecaptchaVerifier('code-button', {
size: 'invisible'
});
recaptchaVerifier.render()
Then, simply call it where needed:
user.multiFactor.getSession().then((multiFactorSession) => {
// Specify the phone number and pass the MFA session.
const phoneInfoOptions = {
phoneNumber: this.state.number,
session: multiFactorSession
};
const phoneAuthProvider = new firebase.auth.PhoneAuthProvider();
// Send SMS verification code.
return phoneAuthProvider.verifyPhoneNumber(
phoneInfoOptions, recaptchaVerifier);
})

How to hide an AntD message after another Promise (API request) completes?

I want to make an API call. When the API call started I display a loading message. I want to stop showing this message when the API call is a success.
This is the message I am using now
message.loading({
content: "Loading...",
duration: 0,});
I don't know how to stop the message when the API call is a success.
The message.loading (and other functions, like message.success, message.info, etc) return a function that closes the message-box when invoked. This is demonstrated in this sample from their docs:
const showThenHide = () => {
// This starts showing the message:
const hide = message.loading('Action in progress..', 0);
setTimeout(hide, 2500); // <-- This invokes the `hide` function after 2.5 seconds
};
showThenHide();
I assume you already have a Promise<T> that represents your API request in-progress. In which case:
const hideMessage = message.loading('Loading..', /*duration:*/ 0);
try {
const apiRequestPromise = someApiClient.doSomething();
const apiRequestRespons = await apiRequestPromise; // You can also inline this await
renderApiResponse( apiRequestRespons );
}
catch ( err ) {
// TODO: Error-handling
}
finally {
hideMessage();
}
It's important to have the hideMessage() invocation in a finally block and not just after the await apiRequestPromise because if an exception is thrown inside the try block (or if you don't have a try block at all) then the message will remain open indefinitely, which isn't what you want.
if you had checked the document of antd about message you would see how they destroy the loading message there:
message.loading(..) return hide function when excute.
to hide the loading, simply call the hide message.
so I can give you an example to handle asynchronous API call:
const hide = message.loading('Loading...',0)
API.getUser(id).then(res => {
//handle response
hide()
}

how to remove firebase.notifications().onNotificationOpened listener?

I am working on a react native project and using react-native-firebase library. Setting up listener is working but I am not able to find a way to remove listener.
I am setting up this listener on homepage so whenever user reach to homepage. Listener get registered multiple times and action multiple times as result.
I want to destroy this listener then again start a new one.
firebase.notifications().onNotificationOpened((notificationOpen) => {
if (notificationOpen) {
const notification: Notification = notificationOpen.notification;
if(notification.data.type){
}
}
});
If anyone can help, that will be appreciated...
You need to call the listener again in order to remove it as mentioned in the docs.
componentDidMount() {
this.notificationOpenedListener = firebase.notifications().onNotificationOpened((notificationOpen) => {
//... Your Stuff
}
}
componentWillUnmount() {
this.notificationOpenedListener();
}

Resources