This implementation makes use of useSyncExternalStore()
that is available in React 18 or via shim.
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 |
Две потенциальные проблемы промисов, которые скорее всего не увидишь во время разработки и очень тяжело повторить, разве что у тебя плохо написан сервер или очень флеки интернет.
Представим какую-то таб группу которая показывается таблицы с разными данными. При переключении между табами нужно загрузить и показать новую таблицу. Не вдаваясь в подробности, попробуем написать дата фетчинг по зову сердца и по первому попавшемуся примеру из документации Реакта:
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> | |
{/* какой-то контент, всё что угодно на странице логина */} |