Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

View alexeyraspopov's full-sized avatar
✍️
Working on something exciting

Oleksii alexeyraspopov

✍️
Working on something exciting
View GitHub Profile

This implementation makes use of useSyncExternalStore() that is available in React 18 or via shim.

Example

Store declaration:

// CounterStore.js
import { createStore } from 'thelib'
import { useCallback, useMemo, useEffect, useSyncExternalStore } from "react";
import { BehaviorSubject, from, firstValueFrom } from "rxjs";
export function useSubjectQuery(query, deps) {
let subject$ = useMemo(() => new BehaviorSubject(), []);
useEffect(() => {
let subscription = from(query()).subscribe({
next: (value) => subject$.next(value),
error: (error) => subject$.error(error),
/** ISC License (c) 2021 Alexey Raspopov */
import { useLayoutEffect, useRef, useState } from "react";
import cns from "./ResponsiveFrame.module.css"
export function ResponsiveFrame({ className, style, children }) {
let sceneRef = useRef();
let [width, height] = useElementSize(sceneRef);
return (
<div className={className} style={style} ref={sceneRef}>
<svg className={cns.svgFrame} width={width} height={height}>
function Observer() {
let head = { prev: null, next: null }
let tail = { prev: null, next: null }
head.next = tail
tail.prev = head
function subscribe(callback) {
let node = { callback, prev: tail.prev, next: tail }
tail.prev.next = node
tail.prev = node

Две потенциальные проблемы промисов, которые скорее всего не увидишь во время разработки и очень тяжело повторить, разве что у тебя плохо написан сервер или очень флеки интернет.

Race Condition

Представим какую-то таб группу которая показывается таблицы с разными данными. При переключении между табами нужно загрузить и показать новую таблицу. Не вдаваясь в подробности, попробуем написать дата фетчинг по зову сердца и по первому попавшемуся примеру из документации Реакта:

function App() {
  let [query, setQuery] = useState(null);
  let [data, setData] = useState(null);

There is a common pattern to implement an observer/event emitter that returns a subscription handler when a new listener is created. This means subscription handler has direct access to the scope that create the listener. Usually, these observers use arrays or sets to store a list of listeners. Removing a listener means using deletion methods that an array or a set provides. Alternatively, the list of listeners can be implemented as a doubly-linked list. This makes both listener insert and delete operations O(1) instead of array/set's complexity. Obviously, there won't be significant performance gain, but no overhead is better than small overhead.

Предположим, у меня есть список айтемов, где у каждого, например, есть кнопка удаления. По нажатию на кнопку просто вызывается какая-то функция, которая работает с backend API.

function ListItem({ data }) {
  return (
    <li className="list-item">
      {/* ... */}
 
/* @flow */
/**
* @example Simple GET request
* let users = await request('/api/users');
*
* @example Cancellable GET request
* let [result, abort] = request('/api/users', { cancellable: true });
*
* @example Simple POST request
* let task = await request('/api/tasks', {
import * as React from 'react';
import { useState } from 'react';
import { useHistory } from 'react-router-dom';
import useAsyncCallback from './useAsyncCallback';
export default function LoginPage() {
let history = useHistory();
return (
<article>
{/* какой-то контент, всё что угодно на странице логина */}