obsidian-react-components icon indicating copy to clipboard operation
obsidian-react-components copied to clipboard

await calls in code blocks

Open MeepTech opened this issue 3 years ago • 6 comments

I have found useEffect as well as the await keyword cannot be used in the jsx: non-component blocks,

I'm trying to use an async function to load file data before passing it to a react component, if you know any workarounds I'd greatly appreciate it. Thanks!

Error:

 await is only valid in async functions and the top level bodies of modules

MeepTech avatar Nov 04 '22 05:11 MeepTech

I was testing this just today (I just discovered this plugin today) and the async/await works with useEffect, you need to set async on the effect function itself. The way I have it is like this:

const [data, setData] = useState({});

...

useEffect(async () => {
  const request = await fetch('url');
  const processedData = await request.json();
  setData(processedData.message)
}, []);

Not sure how you have your code. One thing to note is that I'm using the Component folder feature (I have a separate folder for all my React components and I call them somewhere else).

One thing to keep in mind and be aware when using async/await to perform fetch requests (specially to APIs) is that, when Obsidian detects a change when Live Preview is enabled (which is the default), it runs the formatter again on the entire note, which in return, triggers the React re-render cycle for the entire note, which runs the useEffect again.

If the note is being edited heavily, it will trigger an API request/useEffect render each time it detects a change, even if it's just one character. This could lead to API rate limits or performance hits if the file being loaded is large.

OneComputerGuy avatar Dec 06 '22 01:12 OneComputerGuy

Yea, thanks for the performance heads up, that's good to take into acount... though My issues lie with using the jsx: not jsx:component blocks sadly.

The jsx: blocks aren't turned into react components, so using useEffect doesn't make sense, as hooks must be used inside functional components.

MeepTech avatar Dec 12 '22 16:12 MeepTech

Don't know what's the usage that you currently have for components, but it doesn't seem to be the one indicated by the developer.

The current usage for the block/inline jsx which is defined by jsx: is to only work to call components, not define them.

If you want to define a component, you still need to define it on the component block (using the triple tick and using jsx:component:<ComponentName>) either in the same note or by creating a folder where you can store the components in separate files.

Trying to do something like the following code will never work or will take time to be supported (if the developer deems it necessary):

jsx: useEffect(()=>{}); return(<p>{state}</p>)

or

jsx: return(<p>This is a paragraph</p>)

One thing to keep in mind is the syntax to define component blocks, it has to follow the syntax jsx:component:<ComponentName> changing "<ComponentName>" for the name you want.

If you want, you can post the code block you're trying to create (sanitize any private information first before posting it here) and we can have a look

OneComputerGuy avatar Dec 13 '22 00:12 OneComputerGuy

Don't know what's the usage that you currently have for components, but it doesn't seem to be the one indicated by the developer.

The current usage for the block/inline jsx which is defined by jsx: is to only work to call components, not define them.

If you want to define a component, you still need to define it on the component block (using the triple tick and using jsx:component:<ComponentName>) either in the same note or by creating a folder where you can store the components in separate files.

I'm not trying to define a component, I'm trying to use one with awaited data. I don't think i should need to make a different new component and then invoke it in a separate block every time I need to await anything. That would lead to multiple blocks required for each file just to re-use a component, which defeats the purpose of using react components imho.

Trying to do something like the following code will never work or will take time to be supported (if the developer deems it necessary):

jsx: useEffect(()=>{}); return(<p>{state}</p>)

Yes, I am aware you can't use useEffect outside of a component. I was pointing out how since jsx: is not a component that's not an option.

I want to do something like: (in a jsx: block, NOT a component block)

const data = await getData('Note.md');
<Component data={data}/>

And since a lot of internal obsidian data fetching functions are async, I can't avoid using await easily here.

MeepTech avatar Dec 14 '22 19:12 MeepTech

Just pass the path to the component and have the component do the fetching

johtso avatar Mar 21 '23 02:03 johtso

Just pass the path to the component and have the component do the fetching

Yea, this is probably my best option, though having to do that each time will be a bit annoying. I do wish we'd just be able to use await though haha.

MeepTech avatar Mar 29 '23 14:03 MeepTech