Created
November 27, 2017 10:29
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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