Skip to content

Instantly share code, notes, and snippets.

@ryanflorence
Created March 9, 2019 23:16
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryanflorence/818286f9cb0fefc131a2adb7e765d36c to your computer and use it in GitHub Desktop.
Save ryanflorence/818286f9cb0fefc131a2adb7e765d36c to your computer and use it in GitHub Desktop.
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import makeHookCompat from "./src";
// make a hook as usual
function useMedia(query) {
let [matches, setMatches] = useState(window.matchMedia(query).matches);
useEffect(() => {
let media = window.matchMedia(query);
let listener = () => setMatches(media.matches);
media.addListener(listener);
listener();
return () => media.removeListener(listener);
}, [query]);
return matches;
}
// Here's the normal usage of the hook
function HookApp() {
let small = useMedia("(max-width: 400px)");
let large = useMedia("(min-width: 800px)");
return (
<div className="Media">
<h1>Media</h1>
<p>Small? {small ? "Yep" : "Nope"}.</p>
<p>Large? {large ? "Yep" : "Nope"}.</p>
</div>
);
}
// Since class components can't use hooks, we can wrap the hook in the class
// patterns for state composition: It returns a render prop component and a
// HOC. It's an array so you can name them
let [Media, withMedia] = makeHookCompat(
// pass in the hook
useMedia,
// and then map component props to hook arguments
// so <Media query="..."> will become useQuery(query)
props => [props.query]
);
// And now we can use the hook in a class!
////////////////////////////////////////////////////////////////////////////////
// Render Props
class RenderPropApp extends React.Component {
render() {
return (
<Media query="(max-width: 400px)">
{small => (
<Media query="(min-width: 800px)">
{large => (
<div className="Media">
<h1>Media</h1>
<p>Small? {small ? "Yep" : "Nope"}.</p>
<p>Large? {large ? "Yep" : "Nope"}.</p>
</div>
)}
</Media>
)}
</Media>
);
}
}
ReactDOM.render(<RenderPropApp />, root);
////////////////////////////////////////////////////////////////////////////////
// HOCs
class HOCAppImpl extends React.Component {
render() {
return (
<div className="Media">
<h1>Media</h1>
<p>Large? {this.props.large ? "Yep" : "Nope"}.</p>
</div>
);
}
}
const HOCApp = withMedia(matches => {
// map hook return value to HOC props
return { large: matches };
})(HOCAppImpl);
ReactDOM.render(<HOCApp query="(min-width: 800px)" />, root);
@mDibyo
Copy link

mDibyo commented Mar 11, 2019

Hey @ryanflorence, I built something recently that let's you use hooks in your class components' render method. That API feels a lot cleaner to me, but maybe it doesn't account for all situations. Would love your feedback!
https://github.com/mDibyo/with-hooks-support

@mgol
Copy link

mgol commented Mar 12, 2019

@mDibyo this package is a hack (it swaps the render method of the provided class component), I wouldn't recommend it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment