@web3-react/core vs ethers
Web3 Frontend Architecture: Wallet Connection State vs. Blockchain Interaction
@web3-react/coreethersSimilar Packages:

Web3 Frontend Architecture: Wallet Connection State vs. Blockchain Interaction

ethers is a complete and compact library for interacting with Ethereum and other EVM-compatible blockchains. It provides utilities for connecting to nodes, signing transactions, and interacting with smart contracts directly. @web3-react/core is a React framework specifically designed to manage wallet connection state and context within a React application. It simplifies the process of connecting wallets, tracking account changes, and handling disconnections using React hooks. While ethers handles the protocol communication, @web3-react handles the UI state management.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
@web3-react/core05,68967.6 kB1773 years agoGPL-3.0-or-later
ethers08,66913 MB6476 months agoMIT

Web3 Frontend Architecture: Wallet Connection State vs. Blockchain Interaction

Building decentralized applications (dApps) requires two distinct layers of functionality: managing the user's wallet connection and interacting with the blockchain itself. @web3-react/core and ethers address these separate needs. ethers is the engine that talks to the blockchain, while @web3-react/core is the steering wheel that manages the connection state in your React UI. Understanding their roles prevents architectural confusion.

🎯 Core Responsibility: Protocol vs. UI State

ethers focuses on the blockchain protocol.

  • It creates providers to read data from nodes.
  • It creates signers to sign transactions with private keys.
  • It does not care about React or UI state.
// ethers: Direct provider creation
import { ethers } from "ethers";

const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const address = await signer.getAddress();

@web3-react/core focuses on React state management.

  • It tracks whether a wallet is connected.
  • It exposes the account address and provider via hooks.
  • It does not sign transactions itself; it gives you the tools to do so.
// @web3-react/core: Hook-based state access
import { useWeb3React } from "@web3-react/core";

function WalletStatus() {
  const { account, provider } = useWeb3React();
  return <div>Connected: {account}</div>;
}

πŸ”Œ Connecting to a Wallet: Manual vs. Hook-Driven

ethers requires you to manually handle the connection logic.

  • You must listen for account changes on window.ethereum.
  • You must manage loading states and errors yourself.
  • More code, but full control over the flow.
// ethers: Manual connection handling
async function connectWallet() {
  try {
    await window.ethereum.request({ method: "eth_requestAccounts" });
    const provider = new ethers.BrowserProvider(window.ethereum);
    // Manually update React state here
  } catch (error) {
    console.error("Connection failed", error);
  }
}

@web3-react/core abstracts connection logic into connectors.

  • You use a pre-built connector (like MetaMask).
  • The hook handles loading, error, and account states automatically.
  • Less boilerplate for standard wallet flows.
// @web3-react/core: Using a connector
import { useWeb3React } from "@web3-react/core";
import { injected } from "@web3-react/injected";

function ConnectButton() {
  const { activate, account } = useWeb3React();
  return <button onClick={() => activate(injected)}>Connect</button>;
}

πŸ“‘ Accessing the Provider: Direct vs. Contextual

ethers gives you the provider instance directly.

  • You instantiate it wherever you need it.
  • You must ensure you are using the same provider instance for consistency.
  • Good for scripts or non-React environments.
// ethers: Instantiating provider locally
const provider = new ethers.JsonRpcProvider("https://mainnet.infura.io/v3/KEY");
const blockNumber = await provider.getBlockNumber();

@web3-react/core provides the provider via React Context.

  • The provider is created by the connector and passed to the hook.
  • Ensures all components use the same active connection.
  • You still use ethers methods on this provider.
// @web3-react/core: Consuming provider from context
import { useWeb3React } from "@web3-react/core";
import { ethers } from "ethers";

function BlockDisplay() {
  const { provider } = useWeb3React();
  // Note: web3-react provider might need wrapping to be ethers-compatible
  const ethersProvider = provider ? new ethers.BrowserProvider(provider) : null;
  return <div>Ready to read</div>;
}

✍️ Signing Transactions: Low-Level vs. Integrated

ethers handles the cryptographic signing directly.

  • You call signer.signTransaction or signer.sendTransaction.
  • You manage gas estimation and nonce manually if needed.
  • Essential for complex contract interactions.
// ethers: Signing and sending
const tx = {
  to: "0xRecipient...",
  value: ethers.parseEther("1.0")
};
const txResponse = await signer.sendTransaction(tx);
await txResponse.wait();

@web3-react/core exposes the signer through the hook.

  • You retrieve the signer from the context.
  • You still use ethers to construct the transaction.
  • It ensures the signer matches the connected account.
// @web3-react/core: Getting signer from context
import { useWeb3React } from "@web3-react/core";

function SendButton() {
  const { account, connector } = useWeb3React();
  // Connector provides the provider/signer logic
  const handleSend = async () => {
    const provider = await connector.getProvider();
    // Use ethers with this provider to sign
  };
  return <button onClick={handleSend}>Send</button>;
}

πŸ”„ Handling Disconnections: Events vs. State Reset

ethers relies on event listeners for network changes.

  • You must listen for accountsChanged or chainChanged.
  • You must manually clear state when users disconnect.
  • Easy to miss edge cases without careful coding.
// ethers: Manual event listening
window.ethereum.on("accountsChanged", (accounts) => {
  if (accounts.length === 0) {
    // Manually reset app state
    logout();
  }
});

@web3-react/core auto-updates React state on events.

  • The hook re-renders when the account changes.
  • Disconnection automatically clears account and provider.
  • Reduces risk of stale state in your UI.
// @web3-react/core: Automatic state update
function NavBar() {
  const { account, active } = useWeb3React();
  // If user disconnects in wallet, 'active' becomes false automatically
  if (!active) return <ConnectButton />;
  return <div>{account}</div>;
}

🀝 Similarities: Shared Ground Between Libraries

While they solve different problems, both libraries are essential for modern dApps and share some common ground.

1. πŸ”— EVM Compatibility

  • Both support Ethereum and EVM-compatible chains (Polygon, Arbitrum, etc.).
  • Both rely on standard RPC methods for communication.
// ethers: Switching networks
await provider.send("wallet_switchEthereumChain", [{ chainId: "0x1" }]);

// @web3-react/core: Connector supports chain switching
// Connector configuration defines supported chain IDs

2. πŸ›‘οΈ Security Best Practices

  • Both encourage using secure providers (like WalletConnect or Injected).
  • Neither stores private keys; they rely on the user's wallet.
// ethers: Using secure signer
const signer = provider.getSigner(); // Keys stay in wallet

// @web3-react/core: No key handling
// Library never touches private keys, only addresses

3. 🧩 Extensibility

  • Both can be extended with custom connectors or providers.
  • Both support TypeScript for type safety.
// ethers: Custom provider
class CustomProvider extends ethers.Provider { /*...*/ }

// @web3-react/core: Custom connector
class CustomConnector extends Connector { /*...*/ }

πŸ“Š Summary: Key Differences

Featureethers@web3-react/core
Primary RoleπŸ“‘ Blockchain Communicationβš›οΈ React State Management
ConnectionπŸ› οΈ Manual event listenersπŸͺ Hooks and Connectors
Provider AccessπŸ—οΈ Instantiate directlyπŸ“¦ Via Context/Hook
UI Integration❌ None (Logic only)βœ… Built for React
Transaction Signing✍️ Direct method callsπŸ”‘ Via exposed signer
State Updates⚠️ Manual state syncπŸ”„ Automatic re-renders

πŸ’‘ The Big Picture

ethers is the foundation πŸ—οΈβ€”you cannot build a dApp without something to talk to the blockchain. It is required for signing, reading, and writing data. Use it for all protocol-level logic.

@web3-react/core is the interface πŸŽ¨β€”it makes that foundation usable in a React app. It saves you from writing repetitive connection logic and state sync code. Use it to manage the user's session.

Final Thought: Do not choose one over the other. In a React dApp, you will almost always use both. @web3-react/core manages the connection, and ethers uses that connection to interact with the chain. Treat them as complementary layers in your architecture.

How to Choose: @web3-react/core vs ethers

  • @web3-react/core:

    Choose @web3-react/core if you are building a React application and need to manage wallet connection state across components. It provides hooks to access the user's account and provider without manual event listeners. It simplifies the UI logic for connecting and disconnecting wallets. You will still need ethers or a similar library to actually talk to the chain.

  • ethers:

    Choose ethers when you need a reliable library to communicate with the Ethereum blockchain. It handles signing, contract interaction, and provider management directly. You will likely use this alongside a state manager if you are building a React app. It is the standard for low-level Ethereum interaction.

README for @web3-react/core

@web3-react/core