Integrating NEAR Protocol into a React or Next.js application is straightforward with the near-api-js library and the NEAR Wallet Selector. This guide covers the complete integration from wallet connection to contract interactions.
Setup
Install the required packages:
npm install near-api-js @near-wallet-selector/core @near-wallet-selector/my-near-wallet @near-wallet-selector/meteor-wallet
The wallet selector handles connection to multiple NEAR wallets (MyNearWallet, Meteor Wallet, Ledger, etc.) with a unified interface.
Wallet Connection
Create a NEAR context provider for your React app:
import { setupWalletSelector } from '@near-wallet-selector/core';
import { setupMyNearWallet } from '@near-wallet-selector/my-near-wallet';
import { setupMeteorWallet } from '@near-wallet-selector/meteor-wallet';
const selector = await setupWalletSelector({
network: 'mainnet',
modules: [
setupMyNearWallet(),
setupMeteorWallet(),
],
});
const modal = setupModal(selector, {
contractId: 'your-contract.near',
});
Display the modal on a button click: modal.show(). The selector manages the connection state and exposes a wallet object for signing transactions.
Reading Contract State
View calls (read-only) do not require wallet connection:
import { providers } from 'near-api-js';
const provider = new providers.JsonRpcProvider({
url: 'https://rpc.mainnet.near.org',
});
const result = await provider.query({
request_type: 'call_function',
account_id: 'your-contract.near',
method_name: 'get_data',
args_base64: Buffer.from(JSON.stringify({ key: 'value' })).toString('base64'),
finality: 'final',
});
const data = JSON.parse(Buffer.from(result.result).toString());
Writing Transactions
Change calls require a signed transaction from the connected wallet:
const wallet = await selector.wallet();
await wallet.signAndSendTransaction({
signerId: accountId,
receiverId: 'your-contract.near',
actions: [
{
type: 'FunctionCall',
params: {
methodName: 'set_data',
args: { key: 'value', data: 'payload' },
gas: '30000000000000',
deposit: '0',
},
},
],
});
Next.js Specific Patterns
NEAR wallet selector uses browser APIs and cannot run server-side. Use dynamic imports with ssr: false for wallet-related components:
import dynamic from 'next/dynamic';
const WalletButton = dynamic(
() => import('../components/WalletButton'),
{ ssr: false }
);
For Next.js App Router, mark wallet components with 'use client' at the top. Store wallet selector initialization in a React context that lazy-initializes on mount.
Production Patterns
Cache contract reads using SWR or React Query to avoid unnecessary RPC calls. NEAR RPCs support read queries up to about 100/second per IP before rate limiting. For high-traffic apps, consider a backend proxy to the NEAR RPC.
Handle wallet disconnection gracefully: users can disconnect from the wallet extension outside your app. Check selector.isSignedIn() on each page load and handle the disconnected state explicitly.
For testnet development, use network: 'testnet' and the testnet wallet at testnet.mynearwallet.com. Create separate contract IDs for testnet and mainnet using environment variables.