t4t5 / nostr-react

React Hooks for Nostr 🦤
MIT License
85 stars 14 forks source link

navigating pages in nostr electron client that uses nostrgg-react #1

Closed wds4 closed 1 year ago

wds4 commented 1 year ago

Hi - thanks for getting this started!

I'm putting together an electron nostr client and so far, with the help of this repo I have a very basic global nostr feed that seems to be functioning in dev mode as well as production. You can find my code here. I import NostrProvider and define the relayUrls here. The main feed is here.

Right now, if you clone my repo and start it via the usual steps:

git clone https://github.com/wds/electron-react-boilerplate-nostr.git your-project-name
cd your-project-name
npm install
npm start

you'll immediately see the main global feed, as expected. You can also see events streaming to the console. (Woohoo!)

However, if you navigate to the one other page that currently exists ("manage channels" - not yet functional) and then back to the main feed page, the feed is gone. From the console, I can see that the websocket connections are still open and receiving events.

Any ideas what I am doing wrong? Should I be closing and reopening the websockets when I navigate to a different page? And does it make sense that I am opening websockets in the renderer process and not the main process? (This is my first time using websockets and still leaning my way around electron.)

Thank you in advance for any insights you may have!

t4t5 commented 1 year ago

Hey @wds4!

Right now the events won't be persisted in the library itself, but it would be cool to add automatic caching to it soon (will look into it)!

For now, I think you can store the events across pages yourself through something like Redux?

In the newest version of nostr-react, you can use the onEvent hook to capture the events and then store them in a Redux store for example:

const { onEvent } = useNostrEvents({
  filter: {
    since: dateToUnix(),
    kinds: [1],
  },
});

onEvent((event) => {
  // Store the event in Redux
});
wds4 commented 1 year ago

Hey @t4t5! I agree with you about automatic caching. I know about redux but I've never used it. I'll plan on trying it out, hopefully soon.

One thing I've discovered playing around with nostr-tools directly is that it's important to close the websocket connection whenever the user navigates to a different page. So for example, for any component with:

await relay.connect()

I currently add a listener that executes:

relay.close()

whenever the user clicks a navigation button that directs to a different page. If I don't do this, then the page won't function when I return to it. I'm not sure yet how to accomplish this with nostr-react. I'll push the code when I get a chance so it'll be more clear what I mean.

I'm def excited about this project. I have lots of ideas regarding reputation that I'm eager to implement. 😄

wds4 commented 1 year ago

I've pushed changes to my repo so you can hopefully see what I was talking about in my previous post. Currently, the main page streams all events without filtering. (Eventually I'll want to show only followed users, probably). If you click on a user's pubkey, it will take you to a user page which streams all events from that user.

The way it's currently set up, with each page change I close the relay and then open a new one. On this page you'll see the code to close the relay upon exiting a page:

const aNavButtons = document.getElementsByClassName("leftNavButton");
for(var i = 0; i < aNavButtons.length; i++) {
    (function(index) {
        aNavButtons[index].addEventListener("click", function() {
            relay.close()
        })
    })(i);
}

document.getElementById("userProfileButton").addEventListener("click",function(){
    relay.close()
})

Do you know how I would do that using nostr-react?

An alternative would be to try to open the relay just once -- perhaps in the main process? and then use IPC to communicate with the renderer process, similar to what I do with sqlite3 in my electron-react-boilerplate-sqlite3 template. Then each new page would do something like let sub = relay.sub and then I have to make sure to execute sub.unsub() upon leaving the page. Not sure yet.

dyegolara commented 1 year ago

I'm using react-query to cache the responses from nostr-react. You could use the same lib to add cache support natively or keep it agnostic and add a simple guide for caching for the folks using other query libraries.

t4t5 commented 1 year ago

Hey @t4t5! I agree with you about automatic caching. I know about redux but I've never used it. I'll plan on trying it out, hopefully soon.

One thing I've discovered playing around with nostr-tools directly is that it's important to close the websocket connection whenever the user navigates to a different page. So for example, for any component with:

await relay.connect()

I currently add a listener that executes:

relay.close()

whenever the user clicks a navigation button that directs to a different page. If I don't do this, then the page won't function when I return to it. I'm not sure yet how to accomplish this with nostr-react. I'll push the code when I get a chance so it'll be more clear what I mean.

I'm def excited about this project. I have lots of ideas regarding reputation that I'm eager to implement. 😄

Hey @wds4! Could you try the latest version of react-nostr? I've added some changes to make subscriptions close automatically when the component is unmounted. I think it could help with your usecase! 👍

wds4 commented 1 year ago

I think it works 👍

I have a working version using nostr-tools, but yours loads faster, I presume bc I can connect to multiple relays at once.

I saw earlier in readme you added an unsubscribe function but I guess you buried it so no need for me to set up event listeners, which I like.

I'll let you know when I've pushed changes so you can see it in action!

wds4 commented 1 year ago

Just pushed changes. Currently, I have a main feed (main feed 1 ) which uses nostr-tools, is a bit slow (just one websocket at a time), but shows user name and avatar.

I also have 2 main feeds ( main feed 2 and main feed 3 which use nostr-react -- these are faster but I haven't figured out yet how to load name and avatar into GlobalFeed.

I have a sqlite3 database where I store scraped user profile data including name and picture url. I can incorporate that data into main feed 1 since it's a React component, but not sure how to do that in GlobalFeed which is a function, not a component. (I don't completely understand the difference between a function and a component, although I do know you can't use hooks in a component.)

wds4 commented 1 year ago

Any thoughts @dyegolara or @t4t5 between react-query vs redux on why one might be better than the other for this project? I haven't used either one. From what I can tell, react-query is more specialized for holding an api cache, more lightweight and maybe easier to use for that purpose, whereas redux is more general-purpose. (With the caveat that redux recently added rtk-query which is similar to react-query.)

So I'm trying to contemplate: what are the needs of a nostr app in terms of state management.

dyegolara commented 1 year ago

I like react-query because it handles the cache concept by default. In redux there is more manual setup and thinking. the needs depend on the type of app you are working on (nostr is a lot more than twitter) and state management could be simple or complicated but it all depends on you.

I'd recommend working with what you know already and get familiar with nostr specific things (flows, protocols, shapes, nuances, etc)

wds4 commented 1 year ago

I figured out some of the problems I was having with react functions vs components which means I'm able to use nostr-react throughout my app now 👍

t4t5 commented 1 year ago

I figured out some of the problems I was having with react functions vs components which means I'm able to use nostr-react throughout my app now 👍

Lovely! Looking forward to seeing how the app turns out!

Will close this issue for now, but keep us updated about future problems or requests based on your use case so that we can continue to make the library better! 👍

wds4 commented 1 year ago

I will definitely do that! A lot of my app's basic functionality is already in place. nostr-react has helped me speed up my dev time so thank you!