@concordium/react-components
React components and hooks for implementing features commonly needed by dApps.
The components only manage React state and pass data to application components - no actual HTML is being rendered.
As much as possible is done to help make sure that the dApp is connected to a wallet/account
on the expected network while taking into account that the user may decide to switch network.
Components
Component that bridges @concordium/wallet-connectors
into a React context by
managing connection state and network information.
This component significantly reduces the complexity of integrating with wallets,
even if one only need to support a single protocol and network.
The interface for managing the connectors is exposed through WalletConnectionProps
which is passed to the child component.
Example: Interact with wallets connected to Testnet:
Initialize the network configuration and wrap the component MyAppComponent
that needs to do wallet interaction
in WithWalletConnector
:
import { Network, TESTNET, WalletConnectionProps, WithWalletConnector } from '@concordium/react-components';
function MyRootComponent() {
return <WithWalletConnector network={TESTNET}>{(props) => <MyAppComponent {...props} />}</WithWalletConnector>;
}
function MyAppComponent(props: WalletConnectionProps) {
}
Use props.setActiveConnectorType(...)
from within MyAppComponent
to set up a connector,
and make it available on props.activeConnector
.
This is most easily done using useWalletConnectorSelector
.
Connector types for the Browser Wallet and WalletConnect connectors are usually initialized like so:
export const BROWSER_WALLET = ephemeralConnectorType(BrowserWalletConnector.create);
export const WALLET_CONNECT = ephemeralConnectorType(
WalletConnectConnector.create.bind(undefined, WALLET_CONNECT_OPTS)
);
Initiate a connection by invoking connect
on a connector.
This is most easily done using the hooks useConnection
and useConnect
:
const { activeConnector, network, connectedAccounts, genesisHashes, ... } = props;
const { connection, setConnection, account, genesisHash } = useConnection(activeConnector, connectedAccounts, genesisHashes);
const { connect, isConnecting, connectError } = useConnect(activeConnector, setConnection);
The app uses the function connect
to initiate a new connection from activeConnector
.
The fields isConnecting
and connectError
are used to render the connection status.
Once established, the connection and its state are exposed in the following fields:
connection
: The WalletConnection
object that the app uses to interact with the wallet.
Is undefined
if there is no established connection.account
: The account that connection
is associated with in the wallet
or the empty string if the connection isn't associated with an account.genesisHash
: The hash of the genesis block for the chain that account
lives on
if this value has been reported by the wallet or undefined
otherwise.
This may for instance be used to check that account
lives on the expected network.
Use with care as some wallets don't provide this value reliably.
All the fields hold the value undefined
until the connection has been established and again after it's been disconnected.
See the sample dApp for a complete example.
Hooks
Helper hook for computing the selected/connected/disabled state of a given connector type.
Example: Create a button for toggling a connector
The button accepts all the props
exposed by WithWalletConnector
as well as the particular ConnectorType
that it manages:
import { ConnectorType, useWalletConnectorSelector, WalletConnectionProps } from '@concordium/react-components';
interface Props extends WalletConnectionProps {
connectorType: ConnectorType;
connectorName: string;
}
export function WalletConnectorButton(props: Props) {
const { connectorType, connectorName } = props;
const { isSelected, isConnected, isDisabled, select } = useWalletConnectorSelector(connectorType, props);
return (
);
}
It's important that the ConnectorType
reference passed to the hook is fixed.
See the sample dApp for a complete example.
Hook for managing the state of an input field and lookup smart contract info by its index.
Example: Look up the info of a smart contract by its index specified in an input field
import React, { useState } from 'react';
import { Network, useContractSelector, WalletConnection } from '@concordium/react-components';
import { ConcordiumGRPCClient } from '@concordium/web-sdk';
interface Props {
rpc: ConcordiumGRPCClient | undefined;
}
export function ContractStuff({ rpc }: Props) {
const [input, setInput] = useState('');
const { selected, isLoading, validationError } = useContractSelector(rpc, input);
return (
);
}
Use the hook useGrpcClient
below to obtain a ConcordiumGRPCClient
instance.
See the sample dApp for a complete example.
React hook that obtains a gRPC Web client for interacting with a node on the appropriate network.
Example: Periodically fetch height of "best block"
const rpc = useGrpcClient(network);
const [height, setHeight] = useState<bigint>();
useEffect(() => {
const t = setInterval(() => {
if (rpc) {
rpc.getConsensusStatus()
.then((s) => s.bestBlockHeight)
.then(setHeight)
.catch(console.error);
}
}, intervalMs);
return () => clearTimeout(t);
}, [rpc]);
The client is also used as an input to the hook useContractSelector
above.
Build
Run
yarn
yarn build
to compile the TypeScript files into ./dist
along with type declarations and source maps.