Module: react¶
React hooks and utilities for authentication and records interactions.
Purpose¶
The react
module provides React components, hooks and related utility functions to help manage
authentication and interactions with records, similar to the web
module but designed
specifically to be used with React.
Installation¶
npm install @self.id/react
Common use-cases¶
Configure the Provider¶
The Provider
component must be added at the root of the
application tree in order to use the hooks described below. It can be used to provide a custom
configuration for the Self.ID clients and queries, as well as initial state.
import { Provider } from '@self.id/react'
function App({ children }) {
return <Provider client={{ ceramic: 'testnet-clay' }}>{children}</Provider>
}
Authenticate the user¶
The module provides a React hook to easily initiate an authentication flow for the Viewer
(the "current user" of the app) using an EthereumAuthProvider
instance, notably exported by
the web
module. Once authenticated, the Viewer's cookie is set to the authenticated
DID and writing records associated to the Viewer becomes possible.
import { useViewerConnection } from '@self.id/react'
import { EthereumAuthProvider } from '@self.id/web'
async function createAuthProvider() {
// The following assumes there is an injected `window.ethereum` provider
const addresses = await window.ethereum.request({ method: 'eth_requestAccounts' })
return new EthereumAuthProvider(window.ethereum, addresses[0])
}
// A simple button to initiate the connection flow. A Provider must be present at a higher level
// in the component tree for the `useViewerConnection()` hook to work.
function ConnectButton() {
const [connection, connect, disconnect] = useViewerConnection()
return connection.status === 'connected' ? (
<button
onClick={() => {
disconnect()
}}>
Disconnect ({connection.selfID.id})
</button>
) : 'ethereum' in window ? (
<button
disabled={connection.status === 'connecting'}
onClick={() => {
createAuthProvider().then(connect)
}}>
Connect
</button>
) : (
<p>
An injected Ethereum provider such as{' '}
<a href="https://metamask.io/">MetaMask</a> is needed to authenticate.
</p>
)
}
Auth Session Management¶
Reference did-session for more examples of managing the session for a user. Following code expands on example above.
// ...
const [connection, connect, disconnect] = useViewerConnection()
// ...
// get session string you serialized and stored before, check if still valid (or how much longer)
const sessionStr = ...
const selfid = await connect(new EthereumAuthProvider(window.ethereum, accounts[0]), sessionStr)
// ...
// get session to serialize and store
const session = selfid.client.session //or connection.selfID.client.session
session.serialize()
// ...
Read a viewer record¶
The useViewerRecord
hook loads the record for a given
definition in the index of the current viewer, with the following variants:
- If no viewer is set, no record can be loaded
- If the viewer is not authenticated, the record gets loaded but cannot be mutated
- If the viewer is authenticated, the record gets loaded and be mutated
import { useViewerRecord } from '@self.id/react'
function ShowViewerName() {
const record = useViewerRecord('basicProfile')
const text = record.isLoading
? 'Loading...'
: record.content
? `Hello ${record.content.name || 'stranger'}`
: 'No profile to load'
return <p>{text}</p>
}
Read a public record¶
The usePublicRecord
hook is similar to the
useViewerRecord
hook described above, but reading from the index of an explicitly provided
account rather than the viewer. Public records are read-only, useViewerRecord
must be used in
case mutations are needed.
import { usePublicRecord } from '@self.id/react'
function ShowProfileName({ did }) {
const record = usePublicRecord('basicProfile', did)
const text = record.isLoading
? 'Loading...'
: record.content
? `Hello ${record.content.name || 'stranger'}`
: 'No profile to load'
return <p>{text}</p>
}
Upgrading from 0.3.x to 0.4.x¶
Version 0.4.x
switched the default authentication method and libray from 3id-connect with 3ID DIDs to did-session with PKH DIDs. If you wish to upgrade and still use 3id-connect you can pass a flag and configure your provider as follows. There are no other changes in v0.4.x
, making upgrading not required at the moment if you dont wish too change auth methods, but PKH DIDs will be the recommended account going forward.
import { Provider } from '@self.id/framework'
function App({ children }) {
return <Provider client={{ ceramic: 'testnet-clay' }} threeidConnect={true}>{children}</Provider>
}
**Switching authentication methods with out consideration will change DIDs for users and result in any prior data not being resolved. **
Server-side prefetching¶
Server-side rendering can be used to improve the user experience for the first load of an app or
page. The module exports a RequestClient
class that can be used
to fetch wanted records on the server in order to have them immediately available by the
usePublicRecord
and useViewerRecord
hooks.
The following example shows how this can be used in a Next.js page, using
the ShowViewerName
component created in the previous example:
import { Provider, RequestClient } from '@self.id/react'
export const getServerSideProps = async (ctx) => {
const client = new RequestClient({
ceramic: 'testnet-clay',
// Inject the cookie from the request headers to parse the viewerID
cookie: ctx.req.headers.cookie,
})
if (client.viewerID != null) {
// If the viewerID is set, fetch its profile
await client.prefetch('basicProfile', client.viewerID)
}
return { props: { state: client.getState() } }
}
// Use the state prop injected by the server
export default function Home({ state }) {
return (
<Provider state={state}>
<ShowViewerName />
</Provider>
)
}
Classes¶
Type aliases¶
ProviderProps¶
Ƭ ProviderProps<ModelTypes
>: Object
Type parameters¶
Name | Type |
---|---|
ModelTypes |
extends ModelTypeAliases = CoreModelTypes |
Type declaration¶
Name | Type | Description |
---|---|---|
children |
ReactNode |
- |
client? |
ReactClient <ModelTypes > | WebClientParams <ModelTypes > |
An instance of ReactClient or client configuration parameters . |
queryOptions? |
QueryObserverOptions |
Custom options for the internal react-query configuration. |
state? |
RequestState |
RequestState emitted by a RequestClient instance. |
PublicRecord¶
Ƭ PublicRecord<ContentType
>: Object
A PublicRecord provides an interface for interacting with record stored on Ceramic, associated to a given DID string.
Type parameters¶
Name |
---|
ContentType |
Type declaration¶
Name | Type | Description |
---|---|---|
content? |
ContentType |
Record contents, if loaded. |
error? |
unknown |
Possible error raised when attempting to load the record. |
isError |
boolean |
true when the record failed to load, false otherwise. |
isLoading |
boolean |
true when the record is being loaded, false otherwise. |
RequestClientParams¶
Ƭ RequestClientParams<ModelTypes
>: CoreParams
<ModelTypes
> & { cookie?
: string
}
Type parameters¶
Name | Type |
---|---|
ModelTypes |
extends ModelTypeAliases = CoreModelTypes |
RequestState¶
Ƭ RequestState: Object
Type declaration¶
Name | Type | Description |
---|---|---|
hydrate? |
DehydratedState |
Serialized records to hydrate. |
viewerID? |
string | null |
Viewer ID extracted from cookie value. |
ViewerConnectedContainerProps¶
Ƭ ViewerConnectedContainerProps: Object
Type declaration¶
Name | Type |
---|---|
children |
ReactNode |
renderFallback? |
(connectionState : ViewerConnectionState <ModelTypes >) => null | Element |
ViewerConnectionState¶
Ƭ ViewerConnectionState<ModelTypes
>: { status
: "idle"
} | { promise
: Abortable
<SelfID
<ModelTypes
> | null
> ; provider
: EthereumAuthProvider
; status
: "connecting"
} | { selfID
: SelfID
<ModelTypes
> ; status
: "connected"
} | { error
: Error
; status
: "failed"
}
The viewer connection can be in one of the following states, identified by status
:
idle
: no connection has been attempted.connecting
: attempting to connect using the attachedprovider
. The attachedpromise
can be used to track the connection attempt.connected
: successfully connected with the attachedselfID
.failed
: connection attempted failed with the attachederror
.
Type parameters¶
Name | Type |
---|---|
ModelTypes |
extends ModelTypeAliases = CoreModelTypes |
ViewerID¶
Ƭ ViewerID<ModelTypes
>: PublicID
<ModelTypes
> | SelfID
<ModelTypes
>
A ViewerID can be either a SelfID
or PublicID
instance depending on the current ViewerConnectionState
.
Type parameters¶
Name | Type |
---|---|
ModelTypes |
extends ModelTypeAliases |
ViewerRecord¶
Ƭ ViewerRecord<ContentType
>: { content?
: never
; error?
: never
; isError
: false
; isLoadable
: false
; isLoading
: false
; isMutable
: false
; isMutating
: false
; merge?
: never
; set?
: never
} | { content?
: ContentType
; error?
: unknown
; isError
: boolean
; isLoadable
: true
; isLoading
: boolean
; isMutable
: boolean
; isMutating
: boolean
; merge
: (content
: ContentType
) => Promise
<void
> ; set
: (content
: ContentType
) => Promise
<void
> }
A ViewerRecord provides an interface for interacting with record stored on Ceramic, depending on
the current ViewerID
value:
- If
null
, no interaction is possible with the record. - If it is an instance of
PublicID
, only reads are possible. - If it is an instance of
SelfID
, all interactions (reads and mutations) are possible.
The ViewerRecord object contains the following properties:
isLoadable
:false
if the viewer ID isnull
,true
otherwise.isLoading
:true
when the record is being loaded,false
otherwise.content
: the record contents, if loaded.isError
:true
when the record failed to load,false
otherwise.error
: possible error raised when attempting to load the record.isMutable
:true
if the viewer ID is an instance ofSelfID
,false
otherwise.isMutating
:true
when the record is being mutated as the result of calling the ViewerRecord objectmerge
orset
function,false
otherwise.set
: function used to replace the record contents using theset
method, only available ifisMutating
istrue
.merge
: function used to merge the record contents using themerge
method, only available ifisMutating
istrue
.
Type parameters¶
Name |
---|
ContentType |
Functions¶
Provider¶
▸ Provider<ModelTypes
>(props
): JSX.Element
Top-level provider component for using Self.ID's React APIs.
Type parameters¶
Name | Type |
---|---|
ModelTypes |
extends ModelTypeAliases <Record <string , any >, Record <string , string >, Record <string , string >> = ModelTypes |
Parameters¶
Name | Type |
---|---|
props |
ProviderProps <ModelTypes > |
Returns¶
JSX.Element
ViewerConnectedContainer¶
▸ ViewerConnectedContainer(props
): JSX.Element
| null
Container component for only rendering children
when the viewer is connected.
A renderFallback
function can be provided to render elements when the viewer is not connected.
The current ViewerConnectionState
is injected as function argument.
Parameters¶
Name | Type |
---|---|
props |
ViewerConnectedContainerProps |
Returns¶
JSX.Element
| null
getCookieViewerID¶
▸ getCookieViewerID(cookie?
): string
| null
Extract the possible viewer ID value from the given cookie string value.
Parameters¶
Name | Type |
---|---|
cookie? |
string |
Returns¶
string
| null
useClient¶
▸ useClient<ModelTypes
>(): ReactClient
<ModelTypes
>
Type parameters¶
Name | Type |
---|---|
ModelTypes |
extends ModelTypeAliases <Record <string , any >, Record <string , string >, Record <string , string >> = ModelTypes |
Returns¶
ReactClient
<ModelTypes
>
usePublicRecord¶
▸ usePublicRecord<ModelTypes
, Alias
, ContentType
>(alias
, id
): PublicRecord
<ContentType
| null
>
Hook for accessing the PublicRecord
for a given alias and account (DID or CAIP-10).
Type parameters¶
Name | Type |
---|---|
ModelTypes |
extends ModelTypeAliases <Record <string , any >, Record <string , string >, Record <string , string >> = ModelTypes |
Alias |
extends string | number | symbol = keyof ModelTypes ["definitions" ] |
ContentType |
DefinitionContentType <ModelTypes , Alias > |
Parameters¶
Name | Type |
---|---|
alias |
Alias |
id |
string |
Returns¶
PublicRecord
<ContentType
| null
>
useViewerConnection¶
▸ useViewerConnection<ModelTypes
>(): [ViewerConnectionState
<ModelTypes
>, (provider
: EthereumAuthProvider
) => Promise
<SelfID
<ModelTypes
> | null
>, () => void
]
Hook for handling the viewer's connection lifecycle, returning the following elements:
- The current
ViewerConnectionState
object. - A connection attempt function, taking an
EthereumAuthProvider
argument. - A reset function, clearing the current
ViewerID
.
Type parameters¶
Name | Type |
---|---|
ModelTypes |
extends ModelTypeAliases <Record <string , any >, Record <string , string >, Record <string , string >> = ModelTypes |
Returns¶
[ViewerConnectionState
<ModelTypes
>, (provider
: EthereumAuthProvider
) => Promise
<SelfID
<ModelTypes
> | null
>, () => void
]
useViewerID¶
▸ useViewerID<ModelTypes
>(): ViewerID
<ModelTypes
> | null
Type parameters¶
Name | Type |
---|---|
ModelTypes |
extends ModelTypeAliases <Record <string , any >, Record <string , string >, Record <string , string >> = ModelTypes |
Returns¶
ViewerID
<ModelTypes
> | null
useViewerRecord¶
▸ useViewerRecord<ModelTypes
, Alias
, ContentType
>(alias
): ViewerRecord
<ContentType
| null
>
Hook for accessing the ViewerRecord
for a given alias.
Type parameters¶
Name | Type |
---|---|
ModelTypes |
extends ModelTypeAliases <Record <string , any >, Record <string , string >, Record <string , string >> = ModelTypes |
Alias |
extends string | number | symbol = keyof ModelTypes ["definitions" ] |
ContentType |
DefinitionContentType <ModelTypes , Alias > |
Parameters¶
Name | Type |
---|---|
alias |
Alias |
Returns¶
ViewerRecord
<ContentType
| null
>