1
0
mirror of synced 2026-02-03 18:01:02 -05:00

Compare commits

...

13 Commits

Author SHA1 Message Date
Brandon Bayer
0ce8f06175 bump 2021-02-09 18:39:43 -05:00
Brandon Bayer
86b7af6b20 fix tests 2021-02-09 18:34:53 -05:00
Brandon Bayer
35b318aea0 fix example test 2021-02-09 17:19:00 -05:00
Brandon Bayer
198535e16f fix 2021-02-09 17:06:31 -05:00
Brandon Bayer
003230bba7 fix 2021-02-09 17:04:08 -05:00
Brandon Bayer
65facf9b4c more cleanup 2021-02-09 17:03:01 -05:00
Brandon Bayer
10b12300ca cleanup 2021-02-09 17:02:26 -05:00
Brandon Bayer
77522ae674 cleanup 2021-02-09 17:01:31 -05:00
Brandon Bayer
04c21f398b simplify 2021-02-09 16:58:21 -05:00
Brandon Bayer
2b5ed7a66e Merge branch 'canary' into fix/#1752 2021-02-09 16:21:46 -05:00
Michael Ford
6f84ed8b4f ?? instead of || to avoid blasting away false value 2021-02-08 09:59:06 +00:00
Michael Ford
a41acbe93d Handle the non-suspense case for useQuery 2021-02-08 09:51:52 +00:00
Michael Ford
1f03e73db1 Suspend sessions 2021-02-08 09:34:06 +00:00
10 changed files with 81 additions and 51 deletions

2
.gitignore vendored
View File

@@ -25,3 +25,5 @@ dist
.tsbuildinfo
.nvmrc
**/.test*
examples/auth2
.idea

View File

@@ -2,7 +2,7 @@ import {useSession, useRouter, useMutation, Head} from "blitz"
import logout from "app/auth/mutations/logout"
export default function Layout({title, children}: {title?: string; children: React.ReactNode}) {
const session = useSession()
const session = useSession({suspense: false})
const router = useRouter()
const [logoutMutation] = useMutation(logout)
return (

View File

@@ -1,10 +1,17 @@
import {render} from "test/utils"
import Home from "./index"
import {useCurrentUser} from "app/core/hooks/useCurrentUser"
jest.mock("app/core/hooks/useCurrentUser")
const mockUseCurrentUser = useCurrentUser as jest.MockedFunction<typeof useCurrentUser>
jest.mock("blitz", () => ({
...jest.requireActual("blitz")!,
useQuery: () => [
{
id: 1,
name: "User",
email: "user@email.com",
role: "user",
},
],
}))
test("renders blitz documentation link", () => {
// This is an example of how to ensure a specific item is in the document
@@ -12,12 +19,6 @@ test("renders blitz documentation link", () => {
// when you remove the the default content from the page
// This is an example on how to mock api hooks when testing
mockUseCurrentUser.mockReturnValue({
id: 1,
name: "User",
email: "user@email.com",
role: "user",
})
const {getByText} = render(<Home />)
const element = getByText(/powered by blitz/i)

View File

@@ -1,30 +1,21 @@
import {Suspense} from "react"
import {Head, Link, useSession, useRouterQuery, useMutation, invoke} from "blitz"
import {Head, Link, useSession, useRouterQuery, useMutation, invoke, useQuery} from "blitz"
import getUser from "app/users/queries/getUser"
import trackView from "app/users/mutations/trackView"
import Layout from "app/core/layouts/Layout"
import {useCurrentUser} from "app/core/hooks/useCurrentUser"
// import getUsers from "app/users/queries/getUsers"
const CurrentUserInfo = () => {
const currentUser = useCurrentUser()
const session = useSession()
const [currentUser] = useQuery(getUser, {where: {id: session.userId}})
return <pre>{JSON.stringify(currentUser, null, 2)}</pre>
}
// const Users = () => {
// const [users] = useQuery(getUsers, {})
//
// return <pre style={{maxWidth: "30rem"}}>{JSON.stringify(users, null, 2)}</pre>
// }
const UserStuff = () => {
const session = useSession()
const query = useRouterQuery()
const [trackViewMutation] = useMutation(trackView)
if (session.isLoading) return <div>Loading...</div>
return (
<div>
{!session.userId && (
@@ -48,11 +39,6 @@ const UserStuff = () => {
<Suspense fallback="Loading...">
<CurrentUserInfo />
</Suspense>
{/*
<Suspense fallback="Loading...">
<Users />
</Suspense>
*/}
<button
onClick={async () => {
try {
@@ -94,7 +80,9 @@ const Home = () => (
<img src="/logo.png" alt="blitz.js" />
</div>
<UserStuff />
<Suspense fallback={"Loading..."}>
<UserStuff />
</Suspense>
</main>
<footer>

View File

@@ -6,7 +6,7 @@ type GetUserInput = {
}
export default async function getUser({where}: GetUserInput, ctx: Ctx) {
ctx.session.$authorize()
if (!ctx.session.userId) return null
const user = await db.user.findFirst({where})

View File

@@ -7,7 +7,7 @@ module.exports = withBundleAnalyzer({
middleware: [
sessionMiddleware({
isAuthorized: simpleRolesIsAuthorized,
sessionExpiryMinutes: 4,
// sessionExpiryMinutes: 4,
}),
],
log: {

View File

@@ -12,7 +12,7 @@
"cy:run": "cypress run || cypress run",
"test": "prisma generate && yarn test:jest && yarn test:e2e",
"test:jest": "jest",
"test:server": "blitz prisma migrate deploy --preview-feature && blitz build && blitz start -p 3099",
"test:server": "cross-env NODE_ENV=test blitz prisma migrate deploy --preview-feature && blitz build && cross-env NODE_ENV=test blitz start -p 3099",
"test:e2e": "cross-env NODE_ENV=test start-server-and-test test:server http://localhost:3099 cy:run"
},
"browserslist": [

View File

@@ -1,10 +1,11 @@
import {useState} from "react"
import {useEffect, useState} from "react"
import {getBlitzRuntimeData} from "./blitz-data"
import {COOKIE_CSRF_TOKEN} from "./constants"
import {Ctx} from "./middleware"
import {publicDataStore} from "./public-data-store"
import {IsAuthorizedArgs, PublicData} from "./types"
import {isServer} from "./utils"
import {readCookie} from "./utils/cookie"
import {useIsomorphicLayoutEffect} from "./utils/hooks"
export interface SessionModel extends Record<any, any> {
handle: string
@@ -63,21 +64,35 @@ export interface PublicDataWithLoading extends PublicData {
interface UseSessionOptions {
initialPublicData?: PublicData
suspense?: boolean
}
export const useSession = (options: UseSessionOptions = {}): PublicDataWithLoading => {
const [publicData, setPublicData] = useState(
options.initialPublicData ?? publicDataStore.emptyPublicData,
)
const [isLoading, setIsLoading] = useState(!options.initialPublicData)
const suspense = options?.suspense ?? getBlitzRuntimeData().suspenseEnabled
useIsomorphicLayoutEffect(() => {
let initialState: PublicDataWithLoading
if (options.initialPublicData) {
initialState = {...options.initialPublicData, isLoading: false}
} else if (suspense) {
if (isServer) {
throw new Promise((_) => {})
} else {
initialState = {...publicDataStore.getData(), isLoading: false}
}
} else {
initialState = {...publicDataStore.emptyPublicData, isLoading: true}
}
const [session, setSession] = useState(initialState)
useEffect(() => {
// Initialize on mount
setPublicData(publicDataStore.getData())
setIsLoading(false)
const subscription = publicDataStore.observable.subscribe(setPublicData)
setSession({...publicDataStore.getData(), isLoading: false})
const subscription = publicDataStore.observable.subscribe((data) =>
setSession({...data, isLoading: false}),
)
return subscription.unsubscribe
}, [])
return {...publicData, isLoading}
return session
}

View File

@@ -0,0 +1,26 @@
export const suspend = <T>(promise: Promise<T>) => {
let result: any
let status = "pending"
const suspender = promise.then(
(response) => {
status = "success"
result = response
},
(error) => {
status = "error"
result = error
},
)
return (): T => {
switch (status) {
case "pending":
throw suspender
case "error":
throw result
default:
return result
}
}
}

View File

@@ -34,10 +34,7 @@ export function useQuery<T extends QueryFn, TResult = PromiseReturnType<T>>(
throw new Error("useQuery is missing the first argument - it must be a query function")
}
// TODO - useSession here is a tempory fix for logout query invalidation until RQ v3
// https://github.com/blitz-js/blitz/issues/1711
// NOTE: bug did not present in local dev build. Only via npm bundle
useSession()
const session = useSession({suspense: options?.suspense})
const routerIsReady = useRouter().isReady
const enhancedResolverRpcClient = sanitize(queryFn)
const queryKey = getQueryKey(queryFn, params)
@@ -51,6 +48,7 @@ export function useQuery<T extends QueryFn, TResult = PromiseReturnType<T>>(
config: {
...useDefaultQueryConfig(),
...options,
enabled: options?.enabled ?? !session.isLoading,
},
})
@@ -77,8 +75,7 @@ export function usePaginatedQuery<T extends QueryFn, TResult = PromiseReturnType
throw new Error("usePaginatedQuery is missing the first argument - it must be a query function")
}
// TODO - useSession here is a tempory fix for logout query invalidation until RQ v3
useSession()
const session = useSession({suspense: options?.suspense})
const routerIsReady = useRouter().isReady
const enhancedResolverRpcClient = sanitize(queryFn)
const queryKey = getQueryKey(queryFn, params)
@@ -92,6 +89,7 @@ export function usePaginatedQuery<T extends QueryFn, TResult = PromiseReturnType
config: {
...useDefaultQueryConfig(),
...options,
enabled: options?.enabled ?? !session.isLoading,
},
})
@@ -132,8 +130,7 @@ export function useInfiniteQuery<
throw new Error("useInfiniteQuery is missing the first argument - it must be a query function")
}
// TODO - useSession here is a tempory fix for logout query invalidation until RQ v3
useSession()
const session = useSession({suspense: options?.suspense})
const routerIsReady = useRouter().isReady
const enhancedResolverRpcClient = sanitize(queryFn)
const queryKey = getQueryKey(queryFn, params)
@@ -150,6 +147,7 @@ export function useInfiniteQuery<
config: {
...useDefaultQueryConfig(),
...options,
enabled: options?.enabled ?? !session.isLoading,
},
})