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.
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.
ethers focuses on the blockchain protocol.
// 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.
// @web3-react/core: Hook-based state access
import { useWeb3React } from "@web3-react/core";
function WalletStatus() {
const { account, provider } = useWeb3React();
return <div>Connected: {account}</div>;
}
ethers requires you to manually handle the connection logic.
window.ethereum.// 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.
// @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>;
}
ethers gives you the provider instance directly.
// 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.
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>;
}
ethers handles the cryptographic signing directly.
signer.signTransaction or signer.sendTransaction.// 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.
ethers to construct the transaction.// @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>;
}
ethers relies on event listeners for network changes.
accountsChanged or chainChanged.// 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.
account and provider.// @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>;
}
While they solve different problems, both libraries are essential for modern dApps and share some common ground.
// ethers: Switching networks
await provider.send("wallet_switchEthereumChain", [{ chainId: "0x1" }]);
// @web3-react/core: Connector supports chain switching
// Connector configuration defines supported chain IDs
// 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
// ethers: Custom provider
class CustomProvider extends ethers.Provider { /*...*/ }
// @web3-react/core: Custom connector
class CustomConnector extends Connector { /*...*/ }
| Feature | ethers | @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 |
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.
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.
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.