Created
March 31, 2021 19:08
-
-
Save usmanasif/eec3fa8e0f82ddcca707d72b3927442a to your computer and use it in GitHub Desktop.
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
/** | |
* ***************************SOLUTION*************************** | |
* Following are the three core issues in the given code: | |
* 1) Fallback component missing. This is a mandatory prop plus the whole idea behind concurrent rendering is providing the smooth | |
* experience for instance saving user to see a blank screen while data is not ready. First of all the code given in the problem would not run | |
* but lets assume the code runs then the problem here is why are we using suspense if we are not showing a loading state. | |
* | |
* 2) Fetch on render technique is being used essentially making the suspense of no use. Data is fetched in useEffect and will be set in the state | |
* which at the end will render the data. This may lead to a problem called waterfall. Let's just say once user is loaded we have to render a component | |
* which will show the posts of the user. This will un-necessarily lead us to an un-intentional sequence which could have been parallelized. | |
* | |
* 3) In order to use the Suspense correctly we have to design it in a way where it can provide a mechanism for our fetchUserProfile function to communicate | |
* with react and tell that, data the component requires to load is not ready yet. But the given code doesn't certainly behaves in that scenario. Firstly it | |
* should fetch data in the user profile. Secondly it should not in use effect but using a global resource or so, thirdly api should throw a suspender while in pending state. | |
* | |
* ******************************* BELOW IS THE CODE THAT IMPLEMENTS THE SUSPENSE IN AN APPROPRIATE WAY******************************* | |
*/ | |
import React, { Suspense } from 'react'; | |
import ReactDOM from 'react-dom' | |
// the mechanism which tells react data is not loaded yet---start | |
const fetchUserProfile = (userId) => { | |
let userPromise = getUserPromise(userId) | |
return { | |
user: wrappedFetchUserProfile(userPromise) | |
} | |
} | |
const getUserPromise = (userId) => { | |
return new Promise((resolve, reject) => { | |
setTimeout(() => { | |
resolve({ | |
name: 'Foo'+userId, | |
email: 'Bar' | |
}); | |
}, 3000); | |
}) | |
} | |
const wrappedFetchUserProfile = (promise) => { | |
let status = "pending" | |
let result; | |
let suspender = promise.then(resp => { | |
status = "success" | |
result = resp | |
}).catch(error => { | |
status = "error" | |
result = error | |
}) | |
return ({ | |
read() { | |
switch(status) { | |
case 'pending': | |
throw suspender | |
case 'success': | |
return result | |
case 'error': | |
throw result | |
} | |
} | |
}) | |
} | |
// the mechanism which tells react data is not loaded yet---end | |
const SuspensefulUserProfile = ({ resource, userId}) => { | |
return ( | |
<Suspense fallback={<h1>Loading User {userId}</h1>}> | |
<UserProfile resource={resource} /> | |
</Suspense> | |
); | |
}; | |
const UserProfile = ({ resource }) => { | |
const data = resource.user.read() | |
return ( | |
<> | |
<h1>{data.name}</h1> | |
<h2>{data.email}</h2> | |
</> | |
); | |
}; | |
const UserProfileList = () => ( | |
<> | |
<SuspensefulUserProfile userId={0} resource={fetchUserProfile(1)} /> | |
<SuspensefulUserProfile userId={1} resource={fetchUserProfile(2)} /> | |
<SuspensefulUserProfile userId={2} resource={fetchUserProfile(3)} /> | |
</> | |
); | |
ReactDOM.render( | |
<React.StrictMode> | |
<UserProfileList /> | |
</React.StrictMode>, | |
document.getElementById('root') | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment