Задать вопрос
  • Правильно ли я понимаю причину ререндеров в react+redux?

    @i1yas
    Предположу что вы делаете так:
    const MyForm = () => {
        const name = useSelector((state) => state.user.form.name);
        const surname = useSelector((state) => state.user.form.surname);
        const email = useSelector((state) => state.user.form.email);
        const agree = useSelector((state) => state.user.form.agree);
    
        ...
    }

    В этом случае даже один селектор тригернет ререндер компонента MyForm

    Нужно переработать форму так, чтобы компонент каждого поля внутри себя использовал useSelector:
    const Field = ({ name, ... }) => {
        const value = useSelector(...);
        ...
    }
    const MyForm = () => {
        return (
           <FormContainer ...>
              <Field name="name"/>
              <Field name="surname"/>
              <Field name="email"/>
              ...
           </Form>
        )
    }


    Собственно, это не специфика редакса, это то как хуки и рендеринг в реакте работают. Если ты подписался на значение, то все компненты ниже по дереву будут ререндериться на каждом апдейте. Общее правило - делать подписку на значение как можно ближе к месту использования этого значения.
    Ответ написан
    3 комментария
  • Как применить к классу стиль везде?

    @i1yas
    querySelectorAll возращает колекцию, нужно писать так:
    square.forEach((el) => el.style.backgroundColor = 'green')
    Ответ написан
    1 комментарий
  • Как реализовать автозамену повторяющихся слов в тексте на слова из списка?

    @i1yas
    Можно написать функцию

    function replace($text, $word, $replacements) {
          $r = $replacements;
          $new_text = $text;
          $replacement = null;
          $pattern = "/$word/";
      
          while(true) {
              $replacement = $r[0];
      
              $new_text = preg_replace(
                  $pattern,
                  $replacement,
                  $new_text,
                  1, // заменяем 1 раз
                  $count
              );
      
              if(!$count) return $new_text;
      
              // ротируем замены
              $r = array_merge(array_slice($r, 1), [$replacement]);
          }
      }


    Использование:
    $replaced = replace(
          "First word. Second word. Third word. Forth word.",
          "word",
          ["apple", "banana", "watermelon"]
     );
    print_r($replaced);
    // First apple. Second banana. Third watermelon. Forth apple.


    Замены повторяются по кругу, если совпадений больше
    Ответ написан
  • Как сделать динамический класс?

    @i1yas
    className не принимает на вход функцию, только строки
    Соотвественно передача пропса isWeekend в div бесполезна
    Ответ написан
  • Как перейти по ссылке в VSC начинающийся с @import '@/.......?

    @i1yas
    Если у тебя локальные импорты начинаются с @ и резолвятся в src/*, попробуй добавить jsconfig.json в корень проекта с таким содержимым:
    {
        "compilerOptions": {
          "target": "es6",
          "module": "commonjs",
          "baseUrl": "./",
          "paths": {
            "@*": ["./src/*"]
          }
        },
        "Include": ["./src/**/*"],
        "exclude": ["node_modules", "build", "dist"]
    }
    Ответ написан
    Комментировать
  • Как использовать Docker?

    @i1yas
    1. Да, я так часто делаю, особенно для тех стеков, с которыми я часто не работаю.
    2. Тут смотря что вы имеете ввиду.
    Есть команды docker run/docker exec/docker-compose run, они либо создают контейнер и запускают команду, либо запускают команду на существующем контейнере, например, bash, либо php -a, psql - таким образом можно попасть в интерактивную среду внутри контейнера.
    3. Как настроете. По умолчанию все данные хранятся внутри контейнера и они будут потеряны при следующем рестарте. Для данных, которые нужно сохранять между рестартами, например база данных, есть volume. Если кратко, можно забиндить часть данных внутри контейнера либо на файловую систему, либо в специальное хранилище докера.
    4. Да, можете для примера посмотреть как устроены docker-compose.yml php + mysql + nginx или что вам ближе. Рекомендую просто потыкать, попробовать своей hello world под docker-compose запустить.
    5. Пункт 4, посмотрите какой-нибудь простенький docker-compose.yml, чтобы там БД была и приложение в разных контейнерах, думаю у вас вопросы многие уйдут
    Ответ написан
    Комментировать
  • Какой смысл в \r\n\t\t\t?

    @i1yas
    \r\n - виндовый перенос строки, \t\t\t табуляция, т.е. в коде запрос был отформатирован переносом строки и табуляцией. Скорее всего запрос был скопирован откуда-то, вероятно из логов
    Ответ написан
    Комментировать
  • Как через PDO получить конкретные записи?

    @i1yas
    https://www.w3schools.com/sql/sql_in.asp

    SELECT id, title FROM blog WHERE id IN (1,3,4,5,6)
    Ответ написан
    Комментировать
  • Как создать массив из другого массива?

    @i1yas
    Конечно, ваше решение не будет работать, add_to_array = 'InputMediaPhoto(' + str(id) + ')' - вы просто записываете строку здесь, а должен быть вызов функции. При этом add_to_array не используется, append выполняется на каком-то array к тому же.

    Нужно использовать встроенную функцию map:
    bot.send_media_group(message.from_user.id, list(map(InputMediaPhoto, arrayID)))
    Ответ написан
    Комментировать
  • Почему React.StrictMode ломает приложение?

    @i1yas
    Внутри map делать вот такое
    if (todo.id === id) todo.completed = !todo.completed
    return todo

    Действительно, что могло пойти не так.

    Strict Mode, в частности:
    Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following methods:

    ...
    setState updater functions (the first argument)
    ...


    Вот это выражение:
    if (todo.id === id) todo.completed = !todo.completed
    это сайд-эффект.

    Должно быть:
    if (todo.id === id) return { ...todo, completed: !todo.completed }
    Ответ написан
    2 комментария
  • Почему reducer не видит изменения массива?

    @i1yas
    Документация по редьюсерам https://redux.js.org/basics/reducers
    В частности:
    It's very important that the reducer stays pure. Things you should never do inside a reducer:
    Mutate its arguments;
    Perform side effects like API calls and routing transitions;
    Call non-pure functions, e.g. Date.now() or Math.random().


    Вы мутируете приходящий state

    Чинить надо как-то так:
    export function commentsReducer(state = {data: [], marker: false}, action) {
        switch (action.type) {
            case Comments.ADD_COMMENT: {
                let newData = state.data.slice(); // копируем массив
                newData.push({
                    postId: action.payload.postId,
                    body: action.payload.body,
                    name: action.payload.name,
                    id: state.data[state.data.length - 1].id + 1
                });
                
                // никакого state = ...
                return {...state, is_fetching: false, data: newData};
            }
        }
        return state;
    }
    Ответ написан
    1 комментарий
  • Как изменить рекурсию по дереву?

    @i1yas
    const enumChildNodes = (node, acc = []) => {
      if (node.children.length === 0) // дошли до последнего уровня
        return acc.concat(`${node.tagName} ${node.innerText}`);
      return acc.concat(
        ...[...node.children].map(node => enumChildNodes(node, acc))
      )
    }
    
    enumChildNodes(document.body).forEach(item => console.log(item))
    Ответ написан
  • Что не так с функцией изменения состояния?

    @i1yas
    setStates(prev => {
          prev.map(data => {
            if (data.id === Number(id)) {
              (data.state === 2) ? data.state = 0 : ++data.state
            }
          })
        })


    Функция передаваемая в setStates не возвращает ничего, просто делает map и забывает результат, соотвественно в стейт ложится undefined, у которого метода .map нет, о чем и говорит ошибка
    Нужно добавить:
    return prev.map...

    В map вы делаете похожу ошибку, плюс еще зачем-то мутируете данные.
    if (data.id === Number(id)) {
              (data.state === 2) ? data.state = 0 : ++data.state
            }

    Все что не попадет под это условие станет undefined, т.е. у вас массив будет такой структуры [,,,{},]
    Внутри map надо переписать так:
    data => {
            if (data.id === Number(id)) {
              return (data.state === 2) ? {...data, state: 0} : {...data, state: data.state + 1}          
            }
            return data
    }


    Посмотрите про синтакс стрелочных функций, если не знаете.
    Без фигурных скобок () => expression
    C фигурными скобками () => { return expression }
    Возрат объекта () => ({ someObjectField: ... })
    Ответ написан
    5 комментариев
  • Как установить дефолтное значение в инпуте и изменять его?

    @i1yas
    const [nameValue, setNameValue] = useState(name || "");
    
    <TextField
      ...
      value={nameValue}
      ...
    />
    Ответ написан
  • Правильно ли делать map внутри map?

    @i1yas
    Да, это нормальная практика при обработке вложенных структур, например:

    const topics = [
       {
          topicName: 'Hello there',
          messages: [{...}, {...}]
       },
       {
          topicName: 'Need help',
          messages: [{...}, {...}]
       },
    ]
    
    const msgIdx= topics.map(topic => topic.messages.map(msg => msg.id));


    Только учтите, что структура останется вложенной [ [], [], ...]
    Если нужно получить плоский список, одним мапом не обойтись:
    const msgIdx= topics.map(topic => topic.messages.map(msg => msg.id))
        .reduce((acc, idList) => acc.concat(idList), [])
    Ответ написан
  • Почему props.match == undefined?

    @i1yas
    Вы же сами props скипаете
    <Route path='/dialogue/:id' render={() => <DialogList />}/>

    DialogList не получает никаких пропсов, вы его завернули в компонент, который игнорирует их, делайте тогда так:

    <Route path='/dialogue/:id' render={(props) => <DialogList {...props}/>}/>
    Ответ написан
    1 комментарий
  • Почему ассинхронная функция не возвращает новый массив?

    @i1yas
    Если вы вызывааете функцию getInfo, то естественно получите Promise, это же асинхронная функция.
    Нельзя никак считать результат асинхронной функции синхронно. Await работает только внутри асинхронной функции.
    Так что вам нужно делать getInfo(...).then(res => ...)
    Ответ написан
    Комментировать
  • Удаление элемента из UI в React. Нужно ли передавать предыдущее состояние в setState?

    @i1yas
    newArray = [
     ...todoData.slice(0, idx),
     ...todoData.slice(idx + 1)
    ]

    Ну вот так я бы не советовал объединять массивы, лучше:

    todoData.slice(0, idx).concat(todoData.slice(idx + 1))


    Ну этот вариант скорее всего экономия на спичках, лучше использовать фильтр, если вы не оперируете каким-то невероятным количеством данных на клиенте (что уже странно).
    Ответ написан
    Комментировать
  • Как из строки достать ФИО, г.р. и номер?

    @i1yas
    Я бы в таком случае использовал regexp, но не из-за производительности. Возня с массивом будет достаточно громоздкой, никакого матчинга по сути не будет, только обработка опционального отчества.
    С регуляркой можно проверять дополнительно дату и число:
    $str = 'Иванов Иван Иванович 01.01.1970 353';
    preg_match('/(\w*)\s(\w*)\s?(\w*)\s(\d\d\.\d\d.\d{4})\s(\d+)/u', $str, $match);
    print_r($match);
    Ответ написан
    4 комментария
  • Как сгенерировать массив нечётных чисел без использования циклов?

    @i1yas
    От вас требуется рекурсивное решение.
    С помощью одной функции, с опциональными параметрами:
    function getOddList (count, current = 1, acc = []) {
      if (count == 0) return acc;
      return getOddList(count - 1, current + 2, acc.concat(current))
    }


    С вложенной функцией:
    function getOddList (count) {
      function iter(n, current, acc) {
        if (n == count) return acc;
        return iter(n + 1, current + 2, acc.concat(current))
      }
      return iter(0, 1, []);
    }
    Ответ написан
    Комментировать