Skip to content

Instantly share code, notes, and snippets.

@nvbn
Last active August 29, 2023 13:39
Show Gist options
  • Save nvbn/794971e8c968cacfb799c6427d01f162 to your computer and use it in GitHub Desktop.
Save nvbn/794971e8c968cacfb799c6427d01f162 to your computer and use it in GitHub Desktop.
Hooks with classes
import React from "react";
import Counter from "./Counter";
const App = () => {
return (
<div className="App">
<Counter initialCount={100} />
</div>
);
};
export default App;
import React, { useState, useContext, useEffect, useCallback } from "react";
import {
prop,
asDescriptor,
fromGenerator,
Hookable,
asFunctional,
} from "./hookable";
import Theme from "./Theme";
class Counter extends Hookable {
initialCount = prop();
current = asDescriptor(useState(this.initialCount));
clicked = asDescriptor(useState());
theme = useContext(Theme);
onClick = useCallback(() => {
this.current += 1;
this.clicked = true;
}, [this.current]);
withLogging = fromGenerator(
useEffect,
function*() {
console.log("did mount");
yield;
console.log("did unmount");
},
[],
);
render = this.withLogging(() => (
<div>
<p>
Value:{" "}
<span style={{ color: this.theme.numberColor }}>{this.current}</span>
</p>
{this.clicked && <p>You already clicked!</p>}
<p>Initial value: {this.initialCount}</p>
<button onClick={this.onClick}>Increase</button>
</div>
));
}
export default asFunctional(Counter);
export const prop = () => ({ __isPropGetter: true });
export const asDescriptor = ([val, setVal]) => ({
__isDescriptor: true,
get: () => val,
set: newVal => setVal(newVal),
});
export const fromGenerator = (hook, genFn, deps) => fn => {
const gen = genFn();
hook(() => {
gen.next();
return () => {
gen.next();
};
}, deps);
return fn;
};
export const Hookable = function(props) {
return new Proxy(this, {
set: (obj, name, val) => {
if (val && val.__isPropGetter) {
obj[name] = props[name];
} else if (val && val.__isDescriptor) {
Object.defineProperty(obj, name, val);
} else {
obj[name] = val;
}
return true;
},
});
};
export const asFunctional = cls => props => new cls(props).render();
import { createContext } from "react";
export default createContext({
numberColor: "red",
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment