Как использовать setAttributes вне функции редактирования return

Вопрос или проблема

Это, вероятно, простой случай несоответствия понимания области видимости JavaScript/ESNext или передачи функций (или того и другого), но я не могу заставить setAttributes работать вне основного “return” моей функции редактирования. Я перепробовал множество различных вариантов, и два ниже являются наиболее близкими. В первом варианте, похоже, это как-то работает, но, возможно, есть проблема с областью видимости. Во втором, кажется, что передача функции компоненту не работает. Первое, что я попробовал, это просто использовать это, пытаясь работать так, как это сделали в gutenberg/image-editor.js, но это приводит к странному поведению:

export default function Edit( props ) {
        const {
                attributes: { cwraggDataSourceType, cwraggDataSource,
                    cwraggLocalFile },
                setAttributes,
        } = props;
...
        const DataButton = ( ) => {
                return (<Button
                    isPrimary
                    onClick={ doValidate }>{ __("Validate",
                        'cwra-google-graph-block')}</Button>);
        }
...
        const doValidate = ( ) => { 
                console.log('DataSourceType', cwraggDataSourceType); // выводит "DataSourceType undefined ... это нормально
                console.log('DataSource', cwraggDataSource); // выводит значение, ранее сохраненное в атрибуте cwraggDataSource ... это хорошо
                console.log('LocalFile', cwraggLocalFile); // всегда выводит undefined, так что атрибут не сохраняется
                console.log('Проводится валидация');
                apiFetch( {
                    path: '/cwraggb/v1/setremotedatasrc',
                    method: 'POST', 
                    data: { 'url': cwraggDataSource,
                            'type': cwraggDataSourceType,
                            'postId': post_id } }
                ).then( ( localFileName ) => {
                        console.log("Работаем с ", localFileName); // выводит "Работаем с tmptesty-ZatdoP.tmp", что хорошо и означает, что API-запрос сработал
                        setAttributes( { cwraggLocalFile: localFileName } );
                        console.log('У меня все еще есть ', localFileName); // все еще нормально
                        console.log('cwraggLocalFile равен ', cwraggLocalFile); // выводит "cwraggLocalFile равен undefined", так что ... вызов setAttribute не сработал?
                }).catch( ( error ) => {
                        console.log('долбаный!'); // мы никогда не попадаем сюда (ура!)
                });
        };

        return (
            <Fragment>
                <div>
                    <DataSrcSelectControl />
                    <DataButton />
                </div>
                <div>
                <TextControl
                    label={ __( 'Data URL', 'cwra-google-graph-block' ) }
                    help={ __( 'Введите URL-адрес, из которого нужно получить '
                      + 'JSON файл с данными для графика.',
                      'cwra-google-graph-block') }
                    value={ cwraggDataSource }
                    onChange={ (dataSource) => {
                        setAttributes( { cwraggDataSource: dataSource } ) // это работает нормально
                    }} />
                </div>
                <div className={ "it_worked" }>Генерация графика из
                  { cwraggDataSource }</div>
                <div>Локальный источник данных это { cwraggLocalFile }</div> // это выводит "Локальный источник данных это tmptesty-ZatdoP.tmp" после нажатия кнопки, но если я обновлю и перезагружу страницу, это выводит "Локальный источник данных это" и атрибут пустой????
            </Fragment>
        );
}

Переменная cwraggLocalFile не успешно выводится в консоль при нажатии кнопки (выводит undefined), но обновляется в return после нажатия кнопки, но не сохраняется (после нажатия “Обновить” для поста, он все еще там, но когда я перезагружаю страницу, его нет. Я не могу понять, что здесь происходит. Кажется, что вызов setAttribute и работает, и не работает, так что … я думаю, что у меня какая-то проблема с областью видимости?

После долгих попыток я не смог заставить это работать, поэтому я попробовал другой подход, похожий на это, где он передал функцию setAttributes своему компоненту. Я не думал, что должен был это делать, потому что он делает это в явно другой области видимости, но сейчас я пробую все:

        const doValidate = ( (localFileName, setAttributes) => {
                console.log('Было передано', localFileName);
                console.log('Проводится валидация');

                let dst = default_dst;
                if (cwraggDataSourceType) {
                        dst = cwraggDataSourceType;
                }

                console.log('Используя dst ', dst);
                apiFetch( {
                    path: '/cwraggb/v1/setremotedatasrc',
                    method: 'POST',
                    data: { 'url': cwraggDataSource,
                            'type': dst,
                            'postId': post_id } }
                ).then( ( localFileName ) => {
                        console.log('API вернул ', localFileName); // до сюда все еще работает нормально
                        setAttributes( { cwraggLocalFile: localFileName } );
                        console.log('Получено имя локального файла ', localFileName);
                        console.log('cwraggLocalFile равен ', cwraggLocalFile);
                }).catch( ( error ) => {
                        console.log('долбаный!', error); // но затем мы попадаем сюда! Не нравится setAttributes
                });
        });

        return (
            <Fragment>
                <div>
                    <DataSrcSelectControl />
                    <Button isPrimary
                            onClick={ doValidate( {cwraggLocalFile},
                                {setAttributes}) }>{
                                    __("Validate",
                                    'cwra-google-graph-block')}</Button>
...

Попытавшись использовать этот метод, он попадает в обработчик ошибок и говорит

TypeError: setAttributes is not a function. (В 'setAttributes({ cwraggLocalFile: localFileName })', 'setAttributes' это экземпляр объекта)
(анонимная функция) — edit.js:95
promiseReactionJob

Так что, вероятно, я неправильно передаю функцию setAttributes. Но тот факт, что это происходит и вызывает ошибку здесь, но не в первой попытке выше, заставляет меня думать, что я был ближе к правильному способу сделать это в первой попытке.

Есть ли идеи, что я делаю неправильно или как использовать setAttributes в местах, отличных от основного return вызова?

Я немного запоздал с этим, но для всех, кто ищет похожий ответ – в первом примере я бы сказал, что вы неправильно определили атрибут cwraggDataSource (вы не предоставили код определения блока). Когда атрибут не определяется правильно, он инициализируется как undefined.

Что касается второго примера, вы пытались вызвать setAttributes в функции события, и в ней setAttributes находится вне области видимости.

Ответ или решение

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

Понимание Prоблемы: Область Видимости и setAttributes

  1. Определение атрибутов: Убедитесь, что вы правильно определили атрибуты в вашем блоке. Если атрибут cwraggLocalFile не был корректно определен, он будет инициализирован как undefined. Это может вызывать путаницу при попытке вывода значения в вашем компоненте.

  2. Область видимости: В JavaScript функции имеют лексическую область видимости. Это означает, что setAttributes, доступный в вашем компоненте Edit, доступен для любых вложенных функций, если они не вызываются вне области видимости.

Решение вашей Проблемы

Правильное использование setAttributes

Чтобы вызвать setAttributes успешно из других функций, убедитесь, что вы не потеряли контекст. Давайте оптимизируем вашу функцию doValidate. Вместо передачи setAttributes в качестве аргумента, используйте его напрямую. Вот один из возможных способов сделать это:

export default function Edit( props ) {
    const {
        attributes: { cwraggDataSourceType, cwraggDataSource, cwraggLocalFile },
        setAttributes,
    } = props;

    const doValidate = () => {
        console.log('DataSourceType', cwraggDataSourceType);
        console.log('DataSource', cwraggDataSource);
        console.log('LocalFile', cwraggLocalFile);

        apiFetch({
            path: '/cwraggb/v1/setremotedatasrc',
            method: 'POST',
            data: {
                'url': cwraggDataSource,
                'type': cwraggDataSourceType,
                'postId': post_id
            }
        }).then((localFileName) => {
            console.log("Working with ", localFileName);
            setAttributes({ cwraggLocalFile: localFileName });
            console.log('cwraggLocalFile is now ', localFileName);
        }).catch((error) => {
            console.log('Error occurred:', error);
        });
    };

    const DataButton = () => (
        <Button isPrimary onClick={doValidate}>
            {__("Validate", 'cwra-google-graph-block')}
        </Button>
    );

    return (
        <Fragment>
            <div>
                <DataSrcSelectControl />
                <DataButton />
            </div>
            <div>
                <TextControl
                    label={__('Data URL', 'cwra-google-graph-block')}
                    value={cwraggDataSource}
                    onChange={(dataSource) => {
                        setAttributes({ cwraggDataSource: dataSource })
                    }} 
                />
            </div>
            <div>Local data source is {cwraggLocalFile}</div>
        </Fragment>
    );
}

Важные Моменты:

  1. Передача функций: В вашем втором примере вы пробовали передать setAttributes как аргумент, что недопустимо, так как функция будет вызвана сразу при отрисовке кнопки, а не при нажатии. Игнорируйте это и вызывайте doValidate напрямую в обработчике событий onClick.

  2. Логирование атрибутов: Убедитесь, что атрибуты корректно хранятся и читаются. После вызова setAttributes, новое значение будет доступно в следующем цикле рендеринга компонента.

  3. Обработка ошибок: Убедитесь, что в вашем API правильно обрабатываются ошибки, чтобы избежать путаницы при отладке.

Заключение

Оптимизация работы с setAttributes в Gutenberg требует понимания контекста и области видимости в JavaScript. Убедитесь, что ваш код тщательно проверен на корректность, и вы всегда готовы производить логирование для упрощения отладки. Это поможет вам эффективно управлять состоянием ваших блоков и избежать неприятных сюрпризов.

Оцените материал
Добавить комментарий

Капча загружается...