Duplicate Data Fetching with Redux & Higher Order Components
I'm building a web application with React & Redux + Thunk middleware and am struggling to find the best pattern to connect my components with the data.
I have 3 different presentational components that all rely on the user profile object, which is fetched from the API and stored in Redux state. I have created a higher order function to wrap each of these components, providing them with the user profile object.
This higher order component is connected to Redux and uses selectors to get the data from the Redux store.
const withUser = WrappedComponent => {
class WithUser extends Component {
render = () => {
const {loading, user} = this.props
return <WrappedComponent user={user} loading={loading} {...this.props} />
}
}
const loading = isLoading(['USER_GET'])
const user = getCurrentUser()
return connect(
state => ({ loading: loading(state), user: user(state) }),
{}
)(WithUser)
}
export default withUser
Here is an example of one of my presentational components.
const Profile = props => {
const {name, profileImage} = this.props.user
return (
<Wrapper>
<Avatar src={profileImage} />
<h2>{name}</h2>
</Wrapper>
)
}
export default withUser(Profile)
The crux of my question is: where is the optimal place to fetch the user data? Because I want these components to be entirely independent and context-agnostic, my first thought was to fetch the data using the componentDidMount
lifecycle hook in the higher order component:
componentDidMount = () => {
const {getUser, loading, user} = this.props
if (!loading && !user) getUser()
}
The thought behind this is that if there's not already a user in the Redux state, and another component isn't already fetching it, then call getUser()
. At first, this seemed to work perfectly, but problems arose when I load a page that initialises multiple components wrapped with withUser()
simultaneously. getUser()
sent off multiple requests to fetch the user data, before the loading reducer even picked up that the data was fetching, making !isLoading
redundant.
Is there a better way to approach this situation? All help is appreciated.
UPDATE: I can get a working solution by fetching data using getUser
in the constructor
function of the higher order component.
constructor(props) {
super(props)
const { getUser, loading, user } = props
if (!loading && !user) {
getUser()
}
}
My understanding is that fetching data in the constructor is NOT good practice and should be avoided. Thoughts?
reactjs asynchronous design-patterns redux react-redux
add a comment |
I'm building a web application with React & Redux + Thunk middleware and am struggling to find the best pattern to connect my components with the data.
I have 3 different presentational components that all rely on the user profile object, which is fetched from the API and stored in Redux state. I have created a higher order function to wrap each of these components, providing them with the user profile object.
This higher order component is connected to Redux and uses selectors to get the data from the Redux store.
const withUser = WrappedComponent => {
class WithUser extends Component {
render = () => {
const {loading, user} = this.props
return <WrappedComponent user={user} loading={loading} {...this.props} />
}
}
const loading = isLoading(['USER_GET'])
const user = getCurrentUser()
return connect(
state => ({ loading: loading(state), user: user(state) }),
{}
)(WithUser)
}
export default withUser
Here is an example of one of my presentational components.
const Profile = props => {
const {name, profileImage} = this.props.user
return (
<Wrapper>
<Avatar src={profileImage} />
<h2>{name}</h2>
</Wrapper>
)
}
export default withUser(Profile)
The crux of my question is: where is the optimal place to fetch the user data? Because I want these components to be entirely independent and context-agnostic, my first thought was to fetch the data using the componentDidMount
lifecycle hook in the higher order component:
componentDidMount = () => {
const {getUser, loading, user} = this.props
if (!loading && !user) getUser()
}
The thought behind this is that if there's not already a user in the Redux state, and another component isn't already fetching it, then call getUser()
. At first, this seemed to work perfectly, but problems arose when I load a page that initialises multiple components wrapped with withUser()
simultaneously. getUser()
sent off multiple requests to fetch the user data, before the loading reducer even picked up that the data was fetching, making !isLoading
redundant.
Is there a better way to approach this situation? All help is appreciated.
UPDATE: I can get a working solution by fetching data using getUser
in the constructor
function of the higher order component.
constructor(props) {
super(props)
const { getUser, loading, user } = props
if (!loading && !user) {
getUser()
}
}
My understanding is that fetching data in the constructor is NOT good practice and should be avoided. Thoughts?
reactjs asynchronous design-patterns redux react-redux
add a comment |
I'm building a web application with React & Redux + Thunk middleware and am struggling to find the best pattern to connect my components with the data.
I have 3 different presentational components that all rely on the user profile object, which is fetched from the API and stored in Redux state. I have created a higher order function to wrap each of these components, providing them with the user profile object.
This higher order component is connected to Redux and uses selectors to get the data from the Redux store.
const withUser = WrappedComponent => {
class WithUser extends Component {
render = () => {
const {loading, user} = this.props
return <WrappedComponent user={user} loading={loading} {...this.props} />
}
}
const loading = isLoading(['USER_GET'])
const user = getCurrentUser()
return connect(
state => ({ loading: loading(state), user: user(state) }),
{}
)(WithUser)
}
export default withUser
Here is an example of one of my presentational components.
const Profile = props => {
const {name, profileImage} = this.props.user
return (
<Wrapper>
<Avatar src={profileImage} />
<h2>{name}</h2>
</Wrapper>
)
}
export default withUser(Profile)
The crux of my question is: where is the optimal place to fetch the user data? Because I want these components to be entirely independent and context-agnostic, my first thought was to fetch the data using the componentDidMount
lifecycle hook in the higher order component:
componentDidMount = () => {
const {getUser, loading, user} = this.props
if (!loading && !user) getUser()
}
The thought behind this is that if there's not already a user in the Redux state, and another component isn't already fetching it, then call getUser()
. At first, this seemed to work perfectly, but problems arose when I load a page that initialises multiple components wrapped with withUser()
simultaneously. getUser()
sent off multiple requests to fetch the user data, before the loading reducer even picked up that the data was fetching, making !isLoading
redundant.
Is there a better way to approach this situation? All help is appreciated.
UPDATE: I can get a working solution by fetching data using getUser
in the constructor
function of the higher order component.
constructor(props) {
super(props)
const { getUser, loading, user } = props
if (!loading && !user) {
getUser()
}
}
My understanding is that fetching data in the constructor is NOT good practice and should be avoided. Thoughts?
reactjs asynchronous design-patterns redux react-redux
I'm building a web application with React & Redux + Thunk middleware and am struggling to find the best pattern to connect my components with the data.
I have 3 different presentational components that all rely on the user profile object, which is fetched from the API and stored in Redux state. I have created a higher order function to wrap each of these components, providing them with the user profile object.
This higher order component is connected to Redux and uses selectors to get the data from the Redux store.
const withUser = WrappedComponent => {
class WithUser extends Component {
render = () => {
const {loading, user} = this.props
return <WrappedComponent user={user} loading={loading} {...this.props} />
}
}
const loading = isLoading(['USER_GET'])
const user = getCurrentUser()
return connect(
state => ({ loading: loading(state), user: user(state) }),
{}
)(WithUser)
}
export default withUser
Here is an example of one of my presentational components.
const Profile = props => {
const {name, profileImage} = this.props.user
return (
<Wrapper>
<Avatar src={profileImage} />
<h2>{name}</h2>
</Wrapper>
)
}
export default withUser(Profile)
The crux of my question is: where is the optimal place to fetch the user data? Because I want these components to be entirely independent and context-agnostic, my first thought was to fetch the data using the componentDidMount
lifecycle hook in the higher order component:
componentDidMount = () => {
const {getUser, loading, user} = this.props
if (!loading && !user) getUser()
}
The thought behind this is that if there's not already a user in the Redux state, and another component isn't already fetching it, then call getUser()
. At first, this seemed to work perfectly, but problems arose when I load a page that initialises multiple components wrapped with withUser()
simultaneously. getUser()
sent off multiple requests to fetch the user data, before the loading reducer even picked up that the data was fetching, making !isLoading
redundant.
Is there a better way to approach this situation? All help is appreciated.
UPDATE: I can get a working solution by fetching data using getUser
in the constructor
function of the higher order component.
constructor(props) {
super(props)
const { getUser, loading, user } = props
if (!loading && !user) {
getUser()
}
}
My understanding is that fetching data in the constructor is NOT good practice and should be avoided. Thoughts?
reactjs asynchronous design-patterns redux react-redux
reactjs asynchronous design-patterns redux react-redux
edited Nov 21 '18 at 0:05
bh94
asked Nov 20 '18 at 7:03
bh94bh94
13
13
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
I think it's problem more redux storing than a HOC.A little advise here, store the user data in redux with Array or JSON.Every time fetch a new user data, push it into Array or JSON.
newState.user = [...newState,response.data] //Array
newState.user = { //JSON
...newState,
'profileData': response.data
}
And instead of !loading,use this:
if (!props.profileData) getUser()
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53387823%2fduplicate-data-fetching-with-redux-higher-order-components%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I think it's problem more redux storing than a HOC.A little advise here, store the user data in redux with Array or JSON.Every time fetch a new user data, push it into Array or JSON.
newState.user = [...newState,response.data] //Array
newState.user = { //JSON
...newState,
'profileData': response.data
}
And instead of !loading,use this:
if (!props.profileData) getUser()
add a comment |
I think it's problem more redux storing than a HOC.A little advise here, store the user data in redux with Array or JSON.Every time fetch a new user data, push it into Array or JSON.
newState.user = [...newState,response.data] //Array
newState.user = { //JSON
...newState,
'profileData': response.data
}
And instead of !loading,use this:
if (!props.profileData) getUser()
add a comment |
I think it's problem more redux storing than a HOC.A little advise here, store the user data in redux with Array or JSON.Every time fetch a new user data, push it into Array or JSON.
newState.user = [...newState,response.data] //Array
newState.user = { //JSON
...newState,
'profileData': response.data
}
And instead of !loading,use this:
if (!props.profileData) getUser()
I think it's problem more redux storing than a HOC.A little advise here, store the user data in redux with Array or JSON.Every time fetch a new user data, push it into Array or JSON.
newState.user = [...newState,response.data] //Array
newState.user = { //JSON
...newState,
'profileData': response.data
}
And instead of !loading,use this:
if (!props.profileData) getUser()
answered Nov 20 '18 at 9:45
RootRoot
1,503128
1,503128
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53387823%2fduplicate-data-fetching-with-redux-higher-order-components%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown