React
React Dùng @enfyra/sdk-react cho client-rendered React app sử dụng Enfyra làm backend. Package cung cấp client provider, auth state, query, mutation, storage và realtime hook. Package này chỉ chạy trong browser và dành cho React app deploy riêng, không phải extension chạy bên tro
React
Dùng @enfyra/sdk-react cho client-rendered React app sử dụng Enfyra làm backend. Package cung cấp client provider, auth state, query, mutation, storage và realtime hook.
Package này chỉ chạy trong browser và dành cho React app deploy riêng, không phải extension chạy bên trong Enfyra Admin.
Cài đặt
yarn add @enfyra/sdk-react @enfyra/sdk-core zustand
Thêm Provider
import { EnfyraProvider } from '@enfyra/sdk-react'
export function App() {
return (
<EnfyraProvider
config={{
baseUrl: 'https://admin.example.com',
}}
>
<ApplicationRoutes />
</EnfyraProvider>
)
}
Chỉ cấu hình URL của Enfyra App một lần. Provider tạo client và giữ signed-in session cho các SDK hook.
Truy cập original client
import { useEnfyra } from '@enfyra/sdk-react'
function PublishButton({ articleId }: { articleId: number }) {
const client = useEnfyra()
return (
<button onClick={() => client.post('/articles/publish', { articleId })}>
Publish
</button>
)
}
Xác thực
import { useAuth } from '@enfyra/sdk-react'
function Session() {
const { user, isAuthenticated, pending, error, login, logout, refresh } = useAuth()
if (pending) return <p>Checking session…</p>
if (error) return <button onClick={() => refresh()}>Retry session check</button>
if (isAuthenticated) {
return (
<p>
Signed in as {user?.email}
<button onClick={() => logout()}>Sign out</button>
</p>
)
}
return (
<button onClick={() => login({ email, password, remember: true })}>
Sign in
</button>
)
}
Auth state dùng chung trong provider. Login, logout hoặc refresh cập nhật mọi consumer.
Với cookie OAuth:
const client = useEnfyra()
window.location.href = client.auth.getOAuthRedirectUrl(
'google',
`${window.location.origin}/dashboard`,
)
Query dữ liệu
interface Article {
id: number
title: string
status: string
}
function ArticleList() {
const { data, pending, error, meta, refresh } = useQuery<Article[]>('articles', {
select: ['id', 'title', 'status'],
filter: { status: { _eq: 'published' } },
sort: '-createdAt',
limit: 20,
meta: ['totalCount'],
})
if (pending) return <p>Loading…</p>
if (error) return <button onClick={refresh}>Try again</button>
return (
<ul>
{data?.map((article) => <li key={article.id}>{article.title}</li>)}
</ul>
)
}
Query chạy khi component mount và khi serialized query input thay đổi. Dùng immediate: false cho manual query.
Mutation
function CreateArticle() {
const createArticle = useMutation<Article>('articles', {
operation: 'insert',
onSuccess: () => console.log('Created'),
})
async function submit() {
await createArticle.execute({
data: { title: 'New article', status: 'draft' },
})
}
return (
<button disabled={createArticle.pending} onClick={submit}>
Create
</button>
)
}
Cập nhật và xóa:
const updateArticle = useMutation<Article>('articles', { operation: 'update' })
await updateArticle.execute({ id: articleId, data: { status: 'published' } })
const deleteArticle = useMutation('articles', { operation: 'delete' })
await deleteArticle.execute({ id: articleId })
Hook trả null sau handled failure và expose lỗi trong state. Dùng original client khi code cần throw vào error boundary hoặc đọc đầy đủ error details.
Storage
function UploadField() {
const { upload, uploading, getDownloadUrl } = useStorage()
async function handleFile(file: File) {
const record = await upload(file, { folder: 'customer-documents' })
if (record) console.log(getDownloadUrl(record.id))
}
return (
<input
type="file"
disabled={uploading}
onChange={(event) => {
const file = event.target.files?.[0]
if (file) void handleFile(file)
}}
/>
)
}
Realtime
function Notifications() {
const realtime = useWebSocket('notifications', { immediate: true })
useEffect(() => {
if (!realtime.connected) return
return realtime.on('notification:created', (payload) => {
console.log(payload)
})
}, [realtime.connected, realtime.on])
return realtime.error ? <p>{realtime.error.message}</p> : null
}
Boundary CSR
EnfyraProvider throw khi evaluate trên server. Không dùng @enfyra/sdk-react trong React Server Component hoặc SSR render process. Dùng Next.js adapter khi package đó sẵn sàng; trước thời điểm đó, chỉ dùng @enfyra/sdk-core trong request-scoped server code và tự cấu hình proxy.