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> | |
| {/* какой-то контент, всё что угодно на странице логина */} |