Задать вопрос
  • Что происходит со свойством класса при присвоении извне?

    Потому что если танцевать с js, то танцевать как надо:

    Str.prototype.word = 'word'

    А вообще

    interface StrInterface {
        text: string
        word: string
    }
    
    class Str implements StrInterface {
        text = 'hello'
        word: string = ''
    }
     
    Str.prototype.word = 'word'
     
    const s = new Str()
     
    console.log(s.text)
    console.log(s.word)



    upd: Ситуативно через prototype - да, ты можешь "расширять" классы, но для таких ситуаций придуман "extends", который позволяет тебе расширять класс с дополнительными свойствами. И это будет правильно, потому что присвоение свойств напрямую, либо через тот же prototype - может происходить хаотично, например:

    setInterval(() => {
        ++count
        Str.prototype.word = count % 2 == 0 ? 'word' : 'not word'
    }, 1000)
    
    Str.prototype.word = 'word'


    И это сработает.

    Сделано это из-за GC (garbagecollector).

    И такое хаотичное присвоение свойств (чего-либо) считается плохой практикой. Точно так же со стрелочными функциями, которые создаются заново каждый раз и так-же могут упираться в какую-то кондицию, которая каждое исполнение скрипта может их выполнять в разных вариациях (попробуй экспортировать: export default () => { ... }). Точно так-же - все импорты - иммутабельны. Даже если ты экспортируешь так: export let value = 'word', то при импорте в другой модуль - ты этот value не изменишь, никак.
    Ответ написан
    Комментировать
  • Как реализовать свой простой стейт менеджер для реакта?

    В догонку к комментарию:
    Сама имплементация
    import { useState } from 'react'
    
    class Signal<T> {
        #value: T
        #dispatchers: Set<React.Dispatch<React.SetStateAction<T>>> = new Set()
        constructor(value: T){
            this.#value = value
        }
        get current(): T {
            return this.#value
        }
        set current(value: T){
            if(this.#value !== value){
                this.#value = value
                for(const dispatcher of this.#dispatchers){
                    dispatcher(this.#value)
                }
            }
        }
        subscribe(dispatcher: React.Dispatch<React.SetStateAction<T>>): void {
            if(!(this.#dispatchers.has(dispatcher))){
                this.#dispatchers.add(dispatcher)
            }
        }
    }
    
    const createSignal = <T>(value: T): Signal<T> => new Signal(value)
    
    const useSignal = <T>(signal: Signal<T>): Signal<T> => {
        const [, dispatcher] = useState(signal.current)
        signal.subscribe(dispatcher)
        return signal
    }
    
    export { createSignal, useSignal }

    Экспорт сигналов
    import { createSignal } from '../lib/signals.ts'
    
    export const counter = createSignal(0)

    Компонент, который импортирует и использует сигнал
    import { useSignal } from '../lib/signals.ts'
    import { counter } from './shared_signals.ts'
    
    export const Button = () => {
        const _counter = useSignal(counter)
        return (
            <button onClick={ () => ++_counter.current }>
                Count is { _counter.current }
            </button>
        )
    }

    Клиентский скрипт
    import { hydrateRoot } from 'react-dom/client'
    
    import { Layout } from './Layout.tsx'
    import { Button } from './Button.tsx'
    
    hydrateRoot(
        document,
        <Layout>
            <Button/>
            <Button/>
            <Button/>
            <Button/>
            <Button/>
            <Button/>
            <Button/>
            <Button/>
            <Button/>
            <Button/>
        </Layout>
    )

    При клике на любую кнопку - используется сигнал, который ты создаёшь один раз, экспортируешь его и можешь использовать где угодно, в любом компоненте. Примерно так эти стейт-менеджеры и работают. Они держат состояние/состояния вне компонентов. А работает это из-за самой природы импортов/экспортов. Если ты экспортируешь, например так: export const obj = { count: 0 }, а затем импортируешь этот obj в другом модуле и увеличиваешь count - то этот count будет увеличен в контексте всех модулей, которые его импортировали, либо будут импортировать.
    Ответ написан
    Комментировать
  • Как правильно застримить большой поток из exec(...).stdout в ответ сервера?

    mscmls
    @mscmls Автор вопроса
    Проблема была в размере буффера (опции exec).
    spoiler
    exec('zstd -10', { encoding: 'buffer', maxBuffer: 1024 * 4096 }) // x4

    maxBuffer : Largest amount of data in bytes allowed on stdout or stderr. If exceeded, the child process is terminated and any output is truncated. See caveat at maxBuffer and Unicode. Default: 1024 * 1024.

    Ответ написан
    Комментировать
  • Как задать тригер onchange при изменении value?

    Через dispatchEvent?

    <body>
            <select>
                <option>1</option>
                <option>2</option>
            </select>
            <input class="select-input" type="hidden"/>
            <script>
                const select = document.querySelector('select')
                const hiddenInput = document.querySelector('.select-input')
                const hiddenInputEvent = new InputEvent('change')
                select?.addEventListener('change', e => {
                    hiddenInput.value = e.target.value
                    hiddenInput.dispatchEvent(hiddenInputEvent)
                })
                hiddenInput?.addEventListener('change', e => {
                    console.log(hiddenInput.value)
                })
            </script>
        </body>


    Либо напрямую через пропсы, как вариант
    const select = document.querySelector('select')
                const hiddenInput = document.querySelector('.select-input')
                if(select && hiddenInput){
                        select.onchange = (e) => {
                            hiddenInput.value = e.target.value
                            hiddenInput.onchange?.()
                        }
                        hiddenInput.onchange = (e) => {
                            console.log(hiddenInput.value)
                        }
                    }
    Ответ написан
  • Как Вернуть промис без прописывания .then каждый раз?

    Ну во-первых, твой await x.json() при await - это тот-же then.

    И тебе правильно сказали, что без await и без костылей - ты eventLoop не обыграешь.

    Можно выбрасывать при await и потом ловить то, чем оказывается промис в итоге, можно юзать Promise.withResolvers, что в принципе тоже без await нереально.

    Например (с withResolvers):

    const { promise, resolve, reject } = Promise.withResolvers()
    
    const getProducts = () => fetch('https://fakestoreapi.com/products')
    
    try {
        resolve(
            (await getProducts()).json()
        )
    } catch (e) {
        reject(e)
    }
    
    console.log(
        await promise
    )


    Но тебе выше уже сказали, что такие операции без минимум использования оператора await - нереально исполнить. Не хочешь then - будешь юзать await, не хочешь await - будешь юзать then. Либо создавай своё подобие промисов на костылях, через кастомные события или сигналы.

    P.S.: Чтобы понять, почему нельзя сделать то, что хочешь ты - прочитай то что тебе выше написали, а перед/после прочитай это.
    Ответ написан
    Комментировать
  • Remix js, что происходит с типами?

    Первая ссылка в гугле.

    Попробуй использовать хэлпер "json" из ремикса и в возврате лоадера отдавай не просто объект, а оборачивай его в json({ /* ... */ }). Не пробовал, но насколько я правильно ответ понял на SO - может быть из-за этого.

    P.S. А вообще - смысл оборачивать всё в JsonifyObject и т.д., если можно явно описать ожидаемый/неожиданный объект? Например:

    import { useLoaderData } from 'react-router-dom'
    
    type LoaderProps = {
        themes: {
            all: string[],
            selectedId: string
        }
    } | null
    
    export const Component = () => {
        const data = useLoaderData() as LoaderProps
        return data?.themes ? (
            <>
                Selected theme Id: { data.themes.selectedId }
                All themes: { JSON.stringify(data.themes.all) }
            </>
        ) : (
            <>No themes</>
        )
    }
    
    /// 
    
    export const routes = [
        {
            path: '/',
            element: <Component/>,
            loader: () => ({
                themes: {
                    all: [
                        'light',
                        'dark'
                    ],
                    selectedId: 'light'
                }
            })
        }
        /* ... */
    ]
    Ответ написан
    Комментировать
  • Почему при добавлении навигационной панели на страницу профиля происходит бесконечный цикл запросов на сервер?

    Ну а в компоненте Navbar что происходит?
    Ответ написан
    Комментировать