Skip to main content

Use Tableland with React

Quickly set up a React application with Tableland via an account and database connection.


1. Installation & setup

Create a React app and install Tableland as a dependency.

npx create-react-app my-tableland-app

Then, cd into the project and install Tableland.

npm install --save @tableland/sdk

Under src, find the App component, and import Database from @tableland/sdk. The SDK already provides access to ethers v5—for setting up an account connection, you should also import Signer and providers. Lastly, import useState from react for a simple way to track the signer in your application's state.

src/App.js
import { Database } from "@tableland/sdk";
import { Signer, providers } from "ethers";
import { useState } from "react";

function App() {
return <div></div>;
}

export default App;

2. Connect to a signer

All database creates and writes need a Signer. Create a connectSigner method that prompts the browser for a wallet connection, but note there are others ways to create and track an account connection using purpose built web3 libraries (like wagmi). Here, we'll set this up without additional dependencies.

src/App.js
import { Database } from "@tableland/sdk";
import { Signer, providers } from "ethers";
import { useState } from "react";

async function connectSigner() {
// Establish a connection with the browser wallet's provider.
const provider = new providers.Web3Provider(window.ethereum);
// Request the connected accounts, prompting a browser wallet popup to connect.
await provider.send("eth_requestAccounts", []);
// Create a signer from the returned provider connection.
const signer = provider.getSigner();
// Return the signer
return signer;
}

function App() {
const [signer, setSigner] = useState();
return <div></div>;
}

export default App;

You'll want create some way of calling this connect method, such as a "connect" wallet button with some click handler.

src/App.js
function App() {
const [signer, setSigner] = useState();

async function handleConnect() {
// Connect a signer
const signer = await connectSigner();
setSigner(signer);
}

return (
<div>
<button onClick={async () => handleConnect()}>Connect</button>
</div>
);
}

3. Connect to a Database

Setting up a connection is rather straightforward once you have a signer. Simply create a database instance and pass the signer as a parameter upon instantiation. Depending on your setup, you might want specific methods that take a signer as a parameter and pass it to a Database instantiation.

src/App.js
async function connectDatabase(signer) {
// Establish a connection with the database
const db = new Database({ signer });
// Do create, write, and read operations
}

function App() {
const [signer, setSigner] = useState();

async function handleConnect() {
// Connect a signer
const signer = await connectSigner();
setSigner(signer);
// Connect and interact with the database
await connectDatabase(signer);
}

return (
<div>
<button onClick={async () => handleConnect()}>Connect</button>
</div>
);
}

export default App;

The example here establishes a connection but doesn't do anything else—you could imagine methods that handle table creations and writing data which could take a signer, create a database connection, and do some fine tuned operations.

Also, you could track a database singleton using the useState hook, similar to how the signer is demonstrated.

src/App.js
async function connectDatabase(signer) {
// Establish a connection with the database
const db = new Database({ signer });
// Return the database instance
return db;
}

function App() {
const [signer, setSigner] = useState();
const [database, setDatabase] = useState();

async function handleConnect() {
// Connect a signer
const signer = await connectSigner();
setSigner(signer);
// Connect and interact with the database
const database = await connectDatabase(signer);
setDatabase(database);
}

return (
<div>
<button onClick={async () => handleConnect()}>Connect</button>
</div>
);
}

export default App;

Dealing with local-only private keys

For private variable like wallet private keys, these should be placed in a .env.local file, which is only available server-side. Our component above only connects to things client-side, so you'd need to make some adjustments.

PRIVATE_KEY=your_wallet_private_key

Public variable should exist in a .env file in your project's root and save your private key here. For Next to read an environment variable on the client-side, you'll need to prefix it with VITE.

VITE_VAR=your_public_variable

Then, you can access these with the pattern: import.meta.env.VITE_VAR.