Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(TransactionFeedV2): Persist and rehydrate the first page of the feed #6157

Open
wants to merge 7 commits into
base: slava/feed-v2-track-cross-chain
Choose a base branch
from

Conversation

sviderock
Copy link
Contributor

Description

10th PR of RET-1207. Adds a new feedFirstPage field to the Redux so the first page of the feed can be persisted and rehydrated on the app init.

Test plan

Added test to check a proper rehydration flow for the first page of the feed

Related issues

Backwards compatibility

Yes

Network scalability

If a new NetworkId and/or Network are added in the future, the changes in this PR will:

  • Continue to work without code changes, OR trigger a compilation error (guaranteeing we find it when a new network is added)

@sviderock sviderock changed the title Slava/feed v2 persistence chore(TransactionFeedV2): Persist and rehydrate the first page of the feed Oct 16, 2024
Copy link

codecov bot commented Oct 16, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 88.84%. Comparing base (96ce80a) to head (f144272).

Additional details and impacted files

Impacted file tree graph

@@                        Coverage Diff                        @@
##           slava/feed-v2-track-cross-chain    #6157    +/-   ##
=================================================================
  Coverage                            88.83%   88.84%            
=================================================================
  Files                                  728      728            
  Lines                                30899    30916    +17     
  Branches                              5665     5366   -299     
=================================================================
+ Hits                                 27449    27466    +17     
- Misses                                3254     3408   +154     
+ Partials                               196       42   -154     
Files with missing lines Coverage Δ
src/redux/migrations.ts 97.06% <100.00%> (+<0.01%) ⬆️
src/redux/store.ts 80.00% <ø> (ø)
src/transactions/actions.ts 100.00% <100.00%> (ø)
src/transactions/api.ts 100.00% <100.00%> (ø)
src/transactions/feed/TransactionFeedV2.tsx 92.70% <100.00%> (+0.22%) ⬆️
src/transactions/reducer.ts 98.42% <100.00%> (+0.05%) ⬆️
test/schemas.ts 91.63% <100.00%> (+0.02%) ⬆️

... and 66 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 96ce80a...f144272. Read the comment docs.

Comment on lines +406 to +415
useEffect(
function updatePersistedFeedFirstPage() {
const isFirstPage = originalArgs?.endCursor === FIRST_PAGE_TIMESTAMP

if (isFirstPage && data?.transactions) {
dispatch(updateFeedFirstPage(data.transactions))
}
},
[data?.transactions, originalArgs?.endCursor]
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems we could skip this effect by reacting to the underlying RTK-Query API fetched action, within the transactions reducer, right?

Copy link
Contributor Author

@sviderock sviderock Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeanregisser I'll investigate this! RTK-Query dispatches transactionFeedV2Api/executeQuery/fulfilled action whenever the data fetch promise is successfully fulfilled but I'll need to look if there's a type-safe way of catching this action rather than:

const TYPESAFE_FEED_DATA_RECEIVED_ACTION = "transactionFeedV2Api/executeQuery/fulfilled"

switch (action.type) {
  case TYPESAFE_FEED_DATA_RECEIVED_ACTION:
    return { ...state, ... }
}

But if there's no type-safe way - do you think this ^ approach would be sufficient enought?

Copy link
Contributor Author

@sviderock sviderock Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like there is a type-safe way but it requires the use of createSlice. Then we can use the extraReducers:

 extraReducers: (builder) => {
    builder.addMatcher(
      transactionFeedV2Api.endpoints.login.matchFulfilled,
      (state, { payload }) => {
         // modify the state
      },
    )
  },

But for this we'll need to re-write the existing transactions/reducer.ts to slice.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, moving it to to a slice would be good then.

Comment on lines 40 to 79
extractRehydrationInfo: (action): any => {
if (isRehydrateAction(action)) {
const persistedWeb3 = getRehydratePayload(action, 'web3') as RootState['web3'] | undefined
const walletAddress = persistedWeb3?.account?.toLowerCase() ?? null

const persistedTransactions = getRehydratePayload(action, 'transactions') as
| RootState['transactions']
| undefined
const feedFirstPage = persistedTransactions?.feedFirstPage || []

if (walletAddress && feedFirstPage.length) {
const queryKey = `transactionFeedV2({"address":"${walletAddress}","endCursor":${FIRST_PAGE_TIMESTAMP}})`
return {
mutations: {},
provided: {},
subscriptions: {},
queries: {
[queryKey]: {
status: QueryStatus.fulfilled,
endpointName: 'transactionFeedV2',
requestId: nanoid(),
originalArgs: { address: walletAddress, endCursor: FIRST_PAGE_TIMESTAMP },
startedTimeStamp: Date.now(),
data: { transactions: feedFirstPage },
fulfilledTimeStamp: Date.now(),
error: undefined,
},
},
config: {
online: true,
focused: true,
middlewareRegistered: true,
refetchOnFocus: false,
refetchOnReconnect: false,
refetchOnMountOrArgChange: false,
keepUnusedDataFor: 60,
reducerPath: 'transactionFeedV2Api',
invalidationBehavior: 'delayed',
},
} satisfies RootState['transactionFeedV2Api']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this works, but it feels like it's quite specific to underlying details of RTK-Query.
And could break easily with updates.
What do you think of doing something like const currentData = data.transactions || feedFirstPage at the component instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeanregisser
When RTK-Query fetches the data - it first casts it to undefined and after the request is finished populates it with the data from the response. This means that on every page load there will always be an extra re-render where data?.transactions || feedFirstPage will evaluate to feedFirstPage as data would be still undefined for the time of fetching. And this will subsequently trigger the merge of every page with the feedFirstPage.
I'm sure there is a solution that will work that might be similar to what you've proposed (maybe with the init ref flag and useEffect) but this might introduce more complexity as there's gonna be a new issue of distinguishing between initial first page update and subsequent polling updates.

If there's gonna be an update to the library via renovate - the satisfies RootState['transactionFeedV2Api'] clause will ensure that the errors will be thrown if the underlying structure changes which would force us to update our code alongside the library update.

But the caveat is real indeed, as this creates an extra point of maintenance. Although, from the info I've gathered from the Github issues of RTK-Query related specifically to usage with persisted storage and offline usage - this seems to be the recommended approach by the RTK-Query team themselves. I put the link to one of the issues in the comment above the implementation as it might provide a bit more context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants