Last active
January 2, 2020 06:20
-
-
Save CaptainN/51d89c0a752f94b07132cc1bf1bd6b3f to your computer and use it in GitHub Desktop.
example code for meteor hook
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
// Hook, basic use, everything in one component | |
const MyAccount = () => { | |
const { user, isLoggedIn } = useTracker(() => { | |
const user = Meteor.user() | |
const userId = Meteor.userId() | |
return { | |
user, | |
userId, | |
isLoggedIn: !!userId | |
} | |
}, []) | |
if (!isLoggedIn) { | |
return <div> | |
<Link to="/register">Create an Account</Link> | |
<Link to="/login">Log in</Link> | |
</div> | |
} | |
return <div> | |
<h1>{user.username}</h1> | |
<a href="#" onClick={(e) => { e.preventDefault(); Meteor.logout(); }}>Log out</a> | |
</div>) | |
} | |
// With prefab account hook | |
// Create a reusable hook | |
const useAccount = () => useTracker(() => { | |
const user = Meteor.user() | |
const userId = Meteor.userId() | |
return { | |
user, | |
userId, | |
isLoggedIn: !!userId | |
} | |
}, []) | |
// simply use the hook | |
const MyAccount = () => { | |
const { user, isLoggedIn } = useAccount() | |
if (!isLoggedIn) { | |
return <div> | |
<Link to="/register">Create an Account</Link> | |
<Link to="/login">Log in</Link> | |
</div> | |
} | |
return <div> | |
<h1>{user.username}</h1> | |
<a href="#" onClick={(e) => { e.preventDefault(); Meteor.logout() }}>Log out</a> | |
</div> | |
} | |
// Create the Container | |
const withMyAccount = withTracker((props) => { | |
const user = Meteor.user() | |
const userId = Meteor.userId() | |
return { | |
user, | |
userId, | |
isLoggedIn: !!userId | |
} | |
}) | |
// Create the component | |
const MyAccountComponent = ({user, isLoggedIn} => { | |
if (!isLoggedIn) { | |
return <div> | |
<Link to="/register">Create an Account</Link> | |
<Link to="/login">Log in</Link> | |
</div> | |
} | |
return <div> | |
<h1>{user.username}</h1> | |
<a href="#" onClick={(e) => { e.preventDefault(); Meteor.logout() }}>Log out</a> | |
</div> | |
}) | |
// Now create the containerized component - gets messy with more than one container | |
const MyAccount = withMyAccount(MyAccountComponent) | |
// A more complex component with subscribe and queries and complex deps | |
const MyPage = ({ pageId }) => { | |
const {page, isLoading} = useTracker(() => { | |
const handle = Meteor.subscribe('pages', pageId) | |
return { | |
isLoading: !handle.ready(), | |
page: Pages.findOne(pageId) | |
} | |
}, [pageId]) | |
if (isLoading) { | |
return <div>Page is loading</div> | |
} | |
return <div> | |
<h1>{page.title}</h1> | |
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(page.content)}} /> | |
</div> | |
} | |
// Breaking the more complex component apart | |
const MyPage = ({ pageId }) => { | |
const isLoading = useTracker( | |
() => !Meteor.subscribe('pages', pageId).ready(), | |
[pageId] | |
) | |
const page = useTracker( | |
() => Pages.findOne(pageId), | |
[pageId] | |
) | |
if (isLoading) { | |
return <div>Page is loading</div> | |
} | |
return <div> | |
<h1>{page.title}</h1> | |
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(page.content)}} /> | |
</div> | |
} | |
// the same, with generic hooks | |
const usePageSubscribe = (pageId) => useTracker( | |
() => !Meteor.subscribe('pages', pageId).ready(), | |
[pageId] | |
) | |
const usePage = (pageId) => useTracker( | |
() => Pages.findOne(pageId), | |
[pageId] | |
) | |
const MyPage = ({ pageId }) => { | |
const isLoading = usePageSubscribe(pageId) | |
const page = usePage(pageId) | |
if (isLoading) { | |
return <div>Page is loading</div> | |
} | |
return <div> | |
<h1>{page.title}</h1> | |
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(page.content)}} /> | |
</div> | |
} | |
// Same - with Suspense! | |
const usePageSubscribe = (pageId) => useTracker( | |
() => { | |
// This is a little tricky. We want to be able to resolve the promise | |
// when the subscription is ready, but we only want to throw if the | |
// subscription is not ready yet. | |
let handle | |
const promise = new Promise((resolve, reject) => { | |
handle = Meteor.subscribe('pages', pageId, () => { resolve(false) }) | |
}) | |
const isLoading = !handle.ready() | |
if (isLoading) { | |
throw promise | |
} | |
return isLoading | |
}, | |
[pageId] | |
) | |
const usePage = (pageId) => useTracker( | |
() => Pages.findOne(pageId), | |
[pageId] | |
) | |
const MyPage = ({ pageId }) => { | |
// Now usePageSubscribe will throw to the parent Suspense | |
// when the subscription is not ready! | |
const isLoading = usePageSubscribe(pageId) | |
const page = usePage(pageId) | |
return <div> | |
<h1>{page.title}</h1> | |
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(page.content)}} /> | |
</div> | |
} | |
const ExampleUsingSuspense = () => { | |
return <Suspsene fallback={<Loading />}> | |
<MyPage pageId='my-page-id' /> | |
</Suspsene> | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment