const [data, setData] = useState(null);
useEffect(() => {
const controller = new AbortController()
fetchData(controller.signal).then(setData)
return () => controller.abort()
}, [fetchData, setData])
const data = useMemo(() => array.map(mapper).filter(predicate).reduce(reducer), [array])
const handler = useCallback(() => {
// что-то сделать
}, [])
useEffect(() => {
handler(value)
// если не использовать useCallback, эффект будет срабатывать постоянно
}, [handler, value])
const Foo = ({ dispatch }) => {
const handler = useCallback(() => {
dispatch(action());
}, []);
return (
<Bar onClick={handler} />
);
};
export default connect()(Foo);
const Foo = () => {
const dispatch = useDispatch();
const handler = useCallback(() => {
dispatch(action());
}, []);
return (
<Bar onClick={handler} />
);
};
export default Foo;
const Foo = ({ value }) => {
return (
<Bar value={value} />
);
};
const mapStateToProps = state => ({
value: state.value,
});
export default connect(mapStateToProps)(Foo);
const Foo = () => {
const value = useSelector(state => state.value);
return (
<Bar value={value} />
);
};
export default Foo;
const valueSelector = state => state.value;
const Foo = () => {
const { dispatch, getState, subscribe } = useStore();
const value = valueSelector(getState());
useEffect(() => subscribe(console.log), []);
const handler = useCallback(() => {
dispatch(action());
}, []);
return (
<Bar onClick={handler} value={value} />
);
};
export default Foo;
getStyles<T extends keyof CSSStyleDeclaration>(styles: Array<T>): Record<T, string> {
return styles.reduce((res, style) => {
res[style] = this.$nativeElement.style[style];
return res;
}, {} as Record<T, string>);
}
getStyles<T extends keyof CSSStyleDeclaration>(styles: readonly T[]) {
return styles.reduce((res, style) => {
res[style] = this.$nativeElement.style[style];
return res;
}, {} as Pick<CSSStyleDeclaration, T>);
}
CSSStyleDeclaration
. this
типизировать, а имя метода вместо string
делать keyof this
.abstract class BaseComp {
abstract listeners: readonly (keyof this)[];
attachListeners() {
this.listeners.forEach(name => {
const method = this[name];
if(typeof method == 'function') {
this[name] = method.bind(this);
// attach
}
})
}
onError() {}
}
class Comp extends BaseComp {
listeners = ["onClick", "onError"] as const;
onClick(){}
}
type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T];
function attachListeners<T extends BaseComp2>(component:T, listeners: FunctionPropertyNames<T>[]) {
listeners.forEach(name => {
const method = component[name];
if(typeof method == 'function') {
component[name] = method.bind(component);
// attach
}
})
}
abstract class BaseComp2 {
onError() {}
}
class Comp2 extends BaseComp2 {
constructor() {
super();
attachListeners<Comp2>(this,["onCLick", "onError"]);
}
onCLick(){}
}
interface Object {
entries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][];
}
type TEventType = keyof HTMLElementEventMap;
type TEventCallback = (this: HTMLElement, ev: HTMLElementEventMap[TEventType]) => any;
type IListener = {
[key in TEventType]?: TEventCallback;
};
class ListenerA implements IListener {
public click() {
console.log("ListenerA.click");
}
public mousemove() {
console.log("ListenerA.mousemove");
}
}
class ListenerB implements IListener {
public click() {
console.log("ListenerB.click");
}
}
class DocumentListener {
constructor(...components: IListener[]) {
for (const component of components) {
const proto = Reflect.getPrototypeOf(component);
const events = Reflect.ownKeys(proto)
.filter(key => key !== "contructor") as (keyof IListener)[];
for (const event of events) {
const callback = component[event];
if (callback !== undefined) {
document.body.addEventListener(event, callback);
}
}
}
}
}
const dl = new DocumentListener(new ListenerA(), new ListenerB());
type TEventType = keyof HTMLElementEventMap;
type TEventCallback = (this: HTMLElement, ev: HTMLElementEventMap[TEventType]) => any;
type IEvent = {
event: TEventType;
callback: TEventCallback;
}
interface IListener {
events: IEvent[];
on(event: TEventType, callback: TEventCallback): any;
};
class Listener implements IListener {
events: IEvent[] = [];
on(event: TEventType, callback: TEventCallback) {
this.events.push({event, callback});
}
}
class DocumentListener {
constructor(...components: IListener[]) {
for (const component of components) {
for (const { event, callback } of component.events) {
document.body.addEventListener(event, callback);
}
}
}
}
const l1 = new Listener();
l1.on("click", () => {
console.log("l1.click");
});
const l2 = new Listener();
l2.on("click", () => {
console.log("l2.click");
});
const dl = new DocumentListener(l1, l2);