Skip to content

Instantly share code, notes, and snippets.

@adrianmcli
Created November 27, 2017 10:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adrianmcli/e436154c7fb3cda8a827f4fc1771d624 to your computer and use it in GitHub Desktop.
Save adrianmcli/e436154c7fb3cda8a827f4fc1771d624 to your computer and use it in GitHub Desktop.
An HOC approach to getting web3 (and a truffle contract) for your React-based dapp
import Web3 from 'web3'
const resolveWeb3 = (resolve) => {
let { web3 } = window
const alreadyInjected = typeof web3 !== 'undefined' // i.e. Mist/Metamask
if (alreadyInjected) {
web3 = new Web3(web3.currentProvider)
console.log(`Injected web3 detected.`)
resolve(web3)
} else {
// Fallback to localhost if no web3 injection.
const provider = new Web3.providers.HttpProvider(`http://localhost:9545`)
web3 = new Web3(provider)
console.log(`No web3 instance injected, using Local web3.`)
resolve(web3)
}
}
export default () =>
new Promise((resolve) => {
// Wait for loading completion to avoid race conditions with web3 injection timing.
window.addEventListener(`load`, () => {
resolveWeb3(resolve)
})
// If document has loaded already, try to get Web3 immediately.
if (document.readyState === `complete`) {
resolveWeb3(resolve)
}
})
// This is an example of how you would use this HOC
import React from 'react'
import withWeb3 from './withWeb3'
const MyComponent = ({ web3, accounts, contract }) =>
<div>
<h1>My Dapp</h1>
<pre>{JSON.stringify(web3, null, 4)}</pre>
<pre>{JSON.stringify(accounts, null, 4)}</pre>
<pre>{JSON.stringify(contract, null, 4)}</pre>
</div>
export default withWeb3(MyComponent)
import initContract from 'truffle-contract'
import contractDefinition from 'path/to/contracts/MyContract.json'
export const getAccounts = web3 =>
new Promise((resolve, reject) => {
web3.eth.getAccounts(
(error, accounts) => (error ? reject(error) : resolve(accounts))
)
})
export const getContractInstance = async web3 => {
const contract = initContract(contractDefinition)
contract.setProvider(web3.currentProvider)
// Dirty hack for web3@1.0.0 support for localhost testrpc
// see https://github.com/trufflesuite/truffle-contract/issues/56#issuecomment-331084530
if (typeof contract.currentProvider.sendAsync !== 'function') {
contract.currentProvider.sendAsync = function () {
return contract.currentProvider.send.apply(
contract.currentProvider, arguments
)
}
}
const instance = await contract.deployed()
return instance
}
import React from 'react'
import getWeb3 from './getWeb3'
import { getAccounts, getContractInstance } from './utils'
const withWeb3 = PassedComponent => class extends React.Component {
state = { web3: null, accounts: null, contract: null }
async componentDidMount () {
try {
const web3 = await getWeb3()
const accounts = await getAccounts(web3)
const contract = await getContractInstance(web3)
this.setState({ web3, accounts, contract })
} catch (error) {
alert(`Failed to load web3, accounts, and contract. Check console for details.`)
console.log(error)
}
}
render () {
const { web3, accounts, contract } = this.state
const appReady = web3 && accounts && contract
// Web3 is still loading, let the user know
if (!appReady) {
return <div>Loading web3, accounts, and contract.</div>
}
// Web3 is ready, inject Web3, accounts, and contract into the PassedComponent
return (
<PassedComponent
web3={web3}
accounts={accounts}
contract={contract}
/>
)
}
}
export default withWeb3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment