I am using a boilerplate called trufflebox's react-auth where
getWeb
is called on loading the page (Link to code)- which creates the
web3
object (Link to Code) - and stores
web3
in the Redux store (Link to code)
Problem: When I retrieve the web3
object from the Redux store, it is undefined
, most likely because web3
has not been created yet in Step 2 described above.
What should be the correct way to retrieve web3
from the Redux store only after it has been set?
layouts/test/Test.js
import React, { Component } from 'react';
import store from '../../store';
class Test extends Component {
ponentWillMount() {
this.setState({
web3: store.getState().results.payload.web3Instance
})
this.instantiateContract()
}
instantiateContract() {
console.log(this.state.web3) // UNDEFINED!!
}
render() {
return (
<h1>Test</h1>
)
}
}
export default Test
Everything works if I retrieve web3
again without going to the Redux store:
import React, { Component } from 'react';
import getWeb3 from '../../util/web3/getWeb3';
class Test extends Component {
ponentWillMount() {
getWeb3
.then(results => {
this.setState({
web3: results.payload.web3Instance
})
this.instantiateContract()
})
}
instantiateContract() {
console.log(this.state.web3)
}
render() {
return (
<h1>Test</h1>
)
}
}
export default Test
I am using a boilerplate called trufflebox's react-auth where
getWeb
is called on loading the page (Link to code)- which creates the
web3
object (Link to Code) - and stores
web3
in the Redux store (Link to code)
Problem: When I retrieve the web3
object from the Redux store, it is undefined
, most likely because web3
has not been created yet in Step 2 described above.
What should be the correct way to retrieve web3
from the Redux store only after it has been set?
layouts/test/Test.js
import React, { Component } from 'react';
import store from '../../store';
class Test extends Component {
ponentWillMount() {
this.setState({
web3: store.getState().results.payload.web3Instance
})
this.instantiateContract()
}
instantiateContract() {
console.log(this.state.web3) // UNDEFINED!!
}
render() {
return (
<h1>Test</h1>
)
}
}
export default Test
Everything works if I retrieve web3
again without going to the Redux store:
import React, { Component } from 'react';
import getWeb3 from '../../util/web3/getWeb3';
class Test extends Component {
ponentWillMount() {
getWeb3
.then(results => {
this.setState({
web3: results.payload.web3Instance
})
this.instantiateContract()
})
}
instantiateContract() {
console.log(this.state.web3)
}
render() {
return (
<h1>Test</h1>
)
}
}
export default Test
Share
Improve this question
asked Nov 11, 2017 at 18:42
NyxynyxNyxynyx
63.9k163 gold badges507 silver badges856 bronze badges
1
- Were you able to solve this? Was my answer below able to help point you in the right direction? Please share your progress on this when you can. – scniro Commented Dec 30, 2017 at 18:20
2 Answers
Reset to default 4Resolve the promise just after creating the store
src/store.js
import getWeb3 from './util/web3/getWeb3';
import { createStore } from 'redux';
//... prepare middlewares and other stuffs , then : create store
const store = createStore(/*....configure it as you want..*/);
// Just after creating store, here the engineering:
getWeb3.then(results => {
// Assuming you have suitable reducer
// Assuming the reducer put the payload in state and accessible via "getState().results.payload.web3Instance"
store.dispatch({ type: 'SAVE_WEB3', payload: results.payload.web3Instance });
});
export default store;
In you ./index.js (where you are rendering the whole app) consider to use Provider
ponent as wrapper to pass store behind the seen and have a singleton store.
src/index.js
import { Provider } from 'react-redux';
import store from './store';
ReactDOM.render(
<Provider store={store}>
<Test />
</Provider>
)
Now, in your ponent, connect
HOC will do everything , see ments below :
src/.../Test.js
import { connect } from 'react-redux';
class Test extends Component {
// No need any lifecyle method , "connect" will do everything :)
render() {
console.log(this.props.web3)
return (
<h1>Test</h1>
)
}
}
// Retrieve from Redux STATE and refresh PROPS of ponent
function mapStateToProps(state) {
return {
web3: state.results.payload.web3Instance // since you are using "getState().results.payload.web3Instance"
}
}
export default connect(mapStateToProps)(Test); // the awesome "connect" will refresh props
Maybe try calling instantiateContract
during the ponentWillReceiveProps phase. Check out the following...
ponentWillMount() {
this.setState({
web3: store.getState().results.payload.web3Instance
});
}
instantiateContract() {
console.log(this.state.web3); // hopefully not undefined
}
ponentWillReceiveProps(nextProps) {
if(nextProps.whatever) {
this.instantiateContract();
}
}
render() {
return (
<h1>Test</h1>
)
}
where nextProps.whatever
is what you are mapping from redux (not totally sure what this is given your details). Ideally this is getting fed back into your ponent and when the value either populates or changes, you then call your function
Also, I see a lot of state management here opposed to what I would expect to see done via props
. if ponentWillReceiveProps(nextProps)
is not a good hook given your application architecture, ponentDidUpdate(prevProps, prevState) could be a viable alternative.