4. Fetch Data from Chain
In the fourth chapter of the tutorial on building an end-to-end dapp on Aptos, you will be learning to fetch data from chain.
Our UI logic relies on whether the connected account has created a todo list. If the account has created a todo list, our app should display that list; if not, the app should display a button offering the option to create a new list.
For that, we first need to check if the connected account has a TodoList resource. In our smart contract, whenever someone creates a todo list we create and assign a TodoList resource to their account.
To fetch data from chain, we can use the Aptos TypeScript SDK. The SDK provides classes and functions for us to easily interact and query the Aptos chain.
To get started:
- Stop the local server if running.
 - In the 
clientdirectory, run:npm i @aptos-labs/ts-sdk - In the 
App.tsxfile, import theAptosclass like so: 
import { Aptos } from "@aptos-labs/ts-sdk";
The TypeScript SDK provides us with a Aptos class which is the main entry point into Aptos's API. By initializing Aptos we can query the Aptos chain.
Read more about the Aptos class in the Aptos TypeScript SDK docs.
- In the 
App.tsxfile, add: 
const aptos = new Aptos();
This will initialize a Aptos instance for us.
By default, Aptos will interact with the devnet network, to set up a different network, we can use AptosConfig class.
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";
const aptosConfig = new AptosConfig({ network: Network.MAINNET });
const aptos = new Aptos(aptosConfig);
Our app displays different UIs based on a user resource (i.e if a user has a list ⇒ if a user has a TodoList resource). For that, we need to know the current account connected to our app.
- Import wallet from the wallet adapter React provider:
 
import { useWallet } from "@aptos-labs/wallet-adapter-react";
- Extract the account object from the wallet adapter:
 
function App (
	const { account } = useWallet();
	...
)
The account object is null if there is no account connected; when an account is connected, the account object holds the account information, including the account address.
- Next, we want to fetch the account’s TodoList resource.
Begin by importing 
useEffectby usingjsx import useEffect from "react";Let’s add auseEffecthook to our file that would call a function to fetch the resource whenever our account address changes: 
function App() {
  ...
  useEffect(() => {
    fetchList();
  }, [account?.address]);
  ...
}
- Before creating our 
fetchListfunction, let’s also create a local state to store whether the account has a list: 
function App (
  ...
  const [accountHasList, setAccountHasList] = useState<boolean>(false);
  ...
)
also import useEffect using
import { useState, useEffect } from "react"; 
- Our 
useEffecthook is calling afetchListfunction; let’s create it: 
const fetchList = async () => {
  if (!account) return [];
  // change this to be your module account address
  const moduleAddress = "0xcbddf398841353776903dbab2fdaefc54f181d07e114ae818b1a67af28d1b018";
  try {
    const todoListResource = await aptos.getAccountResource(
      {
        accountAddress:account?.address,
        resourceType:`${moduleAddress}::todolist::TodoList`
      }
    );
    setAccountHasList(true);
  } catch (e: any) {
    setAccountHasList(false);
  }
};
The moduleAddress is the address we publish the module under, i.e the account address you have in your Move.toml file (myaddr).
The provider.getAccountResource()expects an account address that holds the resource we are looking for and a string representation of an on-chain Move struct type.
- account address - is the current connected account (we are getting it from the wallet account object)
 - Move struct type string syntax:
- The account address who holds the move module = our profile account address (You might want to change the 
moduleAddressconst to be your own account address) - The module name the resource lives in = 
todolist - The resource name = 
TodoList 
 - The account address who holds the move module = our profile account address (You might want to change the 
 
If the request succeeds and there is a resource for that account, we want to set our local state to true; otherwise, we would set it to false.
- 
Let’s update
import { Layout, Row, Col } from "antd";to import Button:import { Layout, Row, Col, Button } from "antd"; - 
Let’s update our UI based on the
accountHasListstate: 
return (
  <>
    <Layout>
      <Row align="middle">
        <Col span={10} offset={2}>
          <h1>Our todolist</h1>
        </Col>
        <Col span={12} style={{ textAlign: "right", paddingRight: "200px" }}>
          <WalletSelector />
        </Col>
      </Row>
    </Layout>
    {!accountHasList && (
      <Row gutter={[0, 32]} style={{ marginTop: "2rem" }}>
        <Col span={8} offset={8}>
          <Button
            block
            type="primary"
            style={{ height: "40px", backgroundColor: "#3f67ff" }}
          >
            Add new list
          </Button>
        </Col>
      </Row>
    )}
  </>
);
We now have an Add new list button that appears only if the account doesn’t have a list.
Start the local server with npm start. You should see the Add new list button.
Next, let’s understand how to create a new list by submitting data to chain in chapter 5.