Задать вопрос
  • Почему вместо кириллицы знаки вопросов?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Давно пора запилить аналог вот этого ответа.
    А то же ведь раз в три дня один и тот же вопрос - кракозябры, вопросики, ромбики.
    И везде одна и та же ересь про "meta charset" в ответах.

    Именно в варианте чеклист, чтобы каждый проверял по конкретным пунктам, в которых четко написано, что делать, вместо невнятного мычания "ну у меня там утээф и еще здесь и вот тута"

    В Mysql
    • Кодировка, которую надо выставлять, называется utf8mb4
    • Что там стоит на "всей БД" абсолютно без разницы. Кодировка должна быть указана для таблиц (в отдельных случаях - для поля) при создании. Проверить можно командой SHOW CREATE TABLE table_name

    В PHP
    • Должна быть быть выставлена кодировка соединения с БД
      • в PDO через DSN $dbh = new PDO('mysql:host=...;charset=utf8mb4');
      • в mysqli $mysqli->set_charset('utf8mb4');


    В браузере
    Для того, чтобы браузер корректно отображал кодировку, её надо указать HTTP заголовках.
    • Либо default_charset = "utf-8" в php.ini.
    • Либо руками в коде header('Content-Type: text/html; charset=utf-8');

    Проверять в консоли разработчика: вкладка Сеть, кликаем на запрос, смотрим заголовки
    Ответ написан
    Комментировать
  • В чем разница между undo commit, revert commit и reset branch to commit?

    sergey-kuznetsov
    @sergey-kuznetsov Куратор тега Git
    Автоматизатор
    Там в меню вашей IDE есть ещё несколько методов откатить изменения.
    Это же JetBrains? Все способы подробно описаны в справке, например вот как в IntelliJ IDEA

    Reset удаляет все коммиты выше выбранного. Там предлагается четыре варианта этой команды. Отличия их в том, как поступить с изменениями в рабочем каталоге и в индексе.

    Revert не удаляет коммит, а создаёт новый, который описывает действия необходимые для отмены выбранного коммита.

    Undo позволяет отменить последний коммит. Но изменения коммита предлагает сохранить в новый changelist. Файлы в рабочем каталоге не изменятся и можно будет их подправить и заново закоммитить.

    Drop — удобная команда для удаления произвольного коммита из середины истории. Под капотом там на самом деле выполняется интерактивный rebase, но в автоматическом режиме.

    Revert Selected Changes напоминает Revert, но отменяет изменения отдельного файла, а не всего коммита. Эта команда доступна на Панели изменённых файлов.

    Get позволяет вернуть любой файл к состоянию на определённый коммит в истории. Выберем файл любым удобным способом и контекстное меню Git | Show History покажет все коммиты, в которых изменялся данный файл. Кликнув на нужном коммите правой кнопкой увидим команду Get
    Ответ написан
    Комментировать
  • Почему date-fns локализирует в родительном падеже (вместо именительного)?

    @ikerya Автор вопроса
    Пример из: https://material-ui-pickers.dev/localization/date-fns — как настроить именительный падеж для русской локализации. На всякий случай публикую код здесь:

    import format from "date-fns/format";
    import frLocale from "date-fns/locale/fr";
    import ruLocale from "date-fns/locale/ru";
    import enLocale from "date-fns/locale/en-US";
    import DateFnsUtils from "@date-io/date-fns";
    import MoreIcon from "@material-ui/icons/MoreVert";
    import React, { useState, useCallback } from "react";
    import { IconButton, Menu, MenuItem } from "@material-ui/core";
    import { DatePicker, MuiPickersUtilsProvider } from "@material-ui/pickers";
    
    const localeMap = {
      en: enLocale,
      fr: frLocale,
      ru: ruLocale,
    };
    
    class RuLocalizedUtils extends DateFnsUtils {
      getCalendarHeaderText(date) {
        return format(date, "LLLL", { locale: this.locale });
      }
    
      getDatePickerHeaderText(date) {
        return format(date, "dd MMMM", { locale: this.locale });
      }
    }
    
    class FrLocalizedUtils extends DateFnsUtils {
      getDatePickerHeaderText(date) {
        return format(date, "d MMM yyyy", { locale: this.locale });
      }
    }
    
    const localeUtilsMap = {
      en: DateFnsUtils,
      fr: FrLocalizedUtils,
      ru: RuLocalizedUtils,
    };
    
    const localeFormatMap = {
      en: "MMMM d, yyyy",
      fr: "d MMM yyyy",
      ru: "d MMM yyyy",
    };
    
    const localeCancelLabelMap = {
      en: "cancel",
      fr: "annuler",
      ru: "отмена",
    };
    
    function DateFnsLocalizationExample() {
      const [locale, setLocale] = useState("ru");
      const [anchorEl, setAnchorEl] = useState(null);
      const [selectedDate, handleDateChange] = useState(new Date());
    
      const handleMenuOpen = useCallback(e => {
        e.stopPropagation();
        setAnchorEl(e.currentTarget);
      }, []);
    
      const selectLocale = useCallback(locale => {
        setLocale(locale);
        setAnchorEl(null);
      }, []);
    
      return (
        <MuiPickersUtilsProvider utils={localeUtilsMap[locale]} locale={localeMap[locale]}>
          <DatePicker
            value={selectedDate}
            onChange={handleDateChange}
            format={localeFormatMap[locale]}
            cancelLabel={localeCancelLabelMap[locale]}
            InputProps={{
              endAdornment: (
                <IconButton
                  aria-label="Select locale"
                  onClick={handleMenuOpen}
                  aria-owns={anchorEl ? "locale-menu" : undefined}
                >
                  <MoreIcon />
                </IconButton>
              ),
            }}
          />
    
          <Menu
            id="locale-menu"
            anchorEl={anchorEl}
            open={Boolean(anchorEl)}
            onClose={() => setAnchorEl(null)}
          >
            {Object.keys(localeMap).map(localeItem => (
              <MenuItem
                key={localeItem}
                selected={localeItem === locale}
                onClick={() => selectLocale(localeItem)}
              >
                {localeItem}
              </MenuItem>
            ))}
          </Menu>
        </MuiPickersUtilsProvider>
      );
    }
    
    export default DateFnsLocalizationExample;
    Ответ написан
    1 комментарий
  • Fork на github. Верно ли моё понимание?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Fork - это клон репозитория со всей историей и состоянием на момент его создания. При этом сохраняется связь с оригинальным репозиторием и можно по желанию синхронизировать данные в свой форк оттуда или же делать pull requests в оригинальный репозиторий.

    С какой целью вы делаете себе форк - дело десятое. Если код в оригинальном репозитории позволяет модификацию (open-source), можете с ним делать что хотите - затачивать под себя, разрабатывать фичу которую потом отправите в оригинальный проект и тд. Если делаете модификации чисто для себя - с авторами оригинального проекта ничего согласовывать не нужно. Если хотите фичу им предложить - тогда сначала заведите issue в оригинальном репозитории, обсудите если надо и потом делайте форк и предлагайте pull request.
    Ответ написан
    Комментировать
  • Когда использовать useCallback, useMemo и useEffect?

    @LEXA_JA
    useEffect - это хук, который позволяет использовать сайд эффект. В классах его аналогом было использование componentDidMount, componentDidUpdate и componentWillUnmount. В нем можно делать подписки, отправлять запросы управлять анимацией и т. д.
    const [data, setData] = useState(null);
    
    useEffect(() => {
      const controller = new AbortController()
      fetchData(controller.signal).then(setData)
    
      return () => controller.abort()
    }, [fetchData, setData])


    useCallback и useMemo предназначены для оптимизации. useCallback получает на функцию и массив аргументов, и возвращает одну и туже функцию, до тех пор, пока аргументы не изменились. useMemo отличается тем, что он возвращает не саму функцию, а результат её выполнения. По большому счету они являются взаимозаменямыми.
    Таким образом, useMemo используется для сохранения результатов тяжёлых вычислений, например обработка массива.
    const data = useMemo(() => array.map(mapper).filter(predicate).reduce(reducer), [array])

    А useCallback используется, когда важна постоянность ссылок на функцию. Например, когда мы передаём ссылку в компонент, который использует React.PureComponent или React.memo, или, когда функция используется в качестве аргумента в других хуках
    const handler = useCallback(() => {
      // что-то сделать 
    }, [])
    
    useEffect(() => {
      handler(value)
      // если не использовать useCallback, эффект будет срабатывать постоянно 
    }, [handler, value])
    Ответ написан
    1 комментарий
  • Чем отличаются интеграционное, unit и e2e тестирование на frontend?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Как в юнит тестах тестить нажатие на кнопку? Или мы можем тестить только функцию-обработчик?


    В юнит тестах вы можете тестировать контроллер компонента, что мол он нужное состояние выставляет. DOM проверять не нужно. Механизм биндингов и так хорошо покрыт юнит тестами на уровне фреймворка. Чаще юнитами покрывают сервисы, ресолверы и прочее. Ими проверяют логику работы отдельных маленьких кусочков.

    в интеграционных можно уже потихоньку проверять DOM отдельных компонентов. Просто потому что вы могли опечататься при написании биндингов. Ну то есть цель интеграционных тестов - проверить что в сборке компоненты работают.

    В e2e (end to end) вы загружаете все приложение целиком и имитируете действия пользователей. Причем взаимодействие происходит насквозь. От кнопочки в браузере до запросов в базе данных на сервере (если есть бэкэнд). Это самый медленный вид тестирования и им стоит покрывать только позитивные сценарии.

    Читать про пирамиду тестирования.
    Ответ написан
    Комментировать
  • А какая архитектура reactjs/redux приложения у вас?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Есть два хороших подхода к организации кодовой базы, которые подходят для большинства проектов: File Type First и Feature First:

    Пример Feature First

    Проект:
    /common
      /api
      /components
      /ducks
      /entities
      /sagas
      /selectors
      /utils
    /features
      /Feature1
      /Feature2
      /Feature3
      /Feature4
      ...
      /FeatureN
    /Main
      /pages
      index.js
      App.js
      routes.js
      rootReducer.js
      rootSaga.js
      store.js
    /Auth
      /pages
      index.js
      App.js
      routes.js
      rootReducer.js
      rootSaga.js
      store.js
    ...

    Отдельно взятая Feature:
    /features
      /Accounts
        /components
        index.js
        accountsDucks.js
        accountsSaga.js
        accountsSelectors.js
        accountsApi.js
        Accounts.js
        AccountsContainer.js

     
    Пример File Type First
    /actions
    /common
    /components
      /core
      /Feed
      /Profile
      ...
    /constraints
    /containers
    /entries
    /locales
    /pages
    /reducers
    /utils
    ...


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

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

    Большое количество бойлерплейта это плата которую вы платите за использование redux. Можно писать все константы и редьюсеры руками, можно использовать библиотеки вроде redux-actions и ей подобные. В первом случае вы получаете плюс к гибкости, читаемости и статическому анализу, во втором меньше кода. Я в большинстве проектов предпочитаю первый вариант. Так же создаю шаблоны файлов в Webstorm для asyncActions, contstraints, редьюсера, страницы, компонента и законнекченого компонента.
    В специфичных проектах с множеством CRUD запросов и похожих сущностей есть смысл написать CRUD Boilerpalte.
    Ответ написан
    Комментировать
  • Где лучше всего хранить sass и coffee файлы в Yii2?

    SamDark
    @SamDark
    Yii2 core team
    Вне вебрута потому как в вебруте они не нужны. Я храню в `/assets/`, где `` — `js`, `css`, `less`, `ts` и т.д.
    Ответ написан
    2 комментария
  • Как собрать и минифицировать CSS и JS в Yii2?

    @ph4n70m
    Разобрался.
    Качаешь отсюда https://developers.google.com/closure/compiler/ jar и кидаешь в корень проекта

    npm i yuicompressor - и тащишь yuicompressor.jar тоже в корень

    Создаёшь файл через ./yii asset/template config/minify.php

    Убираешь комментарии с двух строк вверху (где константы) и внизу. А также "раскомменчиваешь"
    'bundles' => [
    'app\assets\AppAsset',
    'yii\web\YiiAsset',
    'yii\web\JqueryAsset',
    ],

    и всё. можешь запускать
    ./yii asset config/minify.php assets/app_min.php

    На выходе будет файл в assets/app_min.php который и подключаешь к проекту
    Ответ написан
    Комментировать
  • Что делать когда кончаются названия для class/id

    @egorinsk
    Вообще, это очень важное и редкое умение, давать имена/названия объектам в программировании. Я часто трачу время именно на то, чтобы подобрать правильное и понятное название (и даже гуглю как аналогичные штуки называют другие разработчики, а также ищу переводы слов), а не написать сам код.

    Что касается вдохновения, тут лучше поменять систему наименований. Например, сделать уникальный класс для блока, а внутри использовать классы с префиксом (по типу предложенной яндексоидами системы БЭМ), вроде:

    .b-news-teaser (внутри b-new-teaser-header, b-new-teaser-list, b-news-teaser-item, b-news-teaser-sticky-flag и так далее), рядом .b-top-comments (внутри классы с таким же префиксом), потом .b-top-articles и так далее. То есть уникальные имена только у блока, а внутренние классы используют префикс.

    Это, кстати, даст верстке определенные свойства «железобетонности» — вы сможете перенести блок с одной страницы на другую, и ничего не сломается. А изменения CSS-стилей в одном блоке новостей не сломают верстку форума (так как у всех блоков используются уникальные имена классов).

    Естественно, вышеописанные свойства у вашей верстки будут только при соблюдении адекватного подхода (а то бывают товарищи, пишущие что-нибудь вроде p { font:… }, или даже * { color: black; } ну дуракам как известно, ничем уже не поможешь).

    Что касается id — их надо избегать или использовать умные именования. Представьте, вы сверстали форму логина на странице, в которой есть field-username и field-password, а завтра вам понадобилось добавить такую же форму внизу (и у вас клик по лейблу в нижней форме начинает прокручивать страницу вверх). Или открыть в попапе. Или еще что-нибудь. Надо либо отказываться от id, либо, если никак, добавлять к ним уникальные префиксы (например #top-form-field-username и #popup-form-field-username).
    Ответ написан
    1 комментарий