Translate

Поиск по этому блогу

среда, 17 июня 2020 г.

Ошибки при работе c React state.

Сегодня мы поговорим об основных, часто встречающихся ошибках, которые часто допускают разработчики при работе с состоянием (state) при разработке React-приложения.



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

Поскольку мы все учимся, это также означает, что мы все также склонны к ошибкам. Хорошо. Цель - стать лучше и стать лучше. Если ты ошибаешься и учишься на ней, у тебя все отлично! Но если вы не научились чему-то новому и продолжаете повторять одни и те же ошибки, ну ... тогда, похоже, вы застаётесь в своей карьере.

В этом духе, вот три распространенных ошибки, которые я часто вижу во время обзоров кода, которые младшие разработчики делают при работе с состоянием компонента React. Мы рассмотрим каждую ошибку и затем обсудим, как ее исправить.

  1. Изменение состояния напрямую.

  2. При изменении состояния компонента важно, чтобы вы возвращали новую копию состояния с изменениями, а не изменяли текущее состояние напрямую. Если вы неправильно измените состояние компонента, алгоритм сравнения React не поймает изменение, и ваш компонент не будет обновляться должным образом. Давайте посмотрим на пример.

    Скажем, у вас есть состояние, которое выглядит так:

    this.state = {
      colors: ['red', 'green', 'blue']
    }
    


    И теперь вы хотите добавить цвет «yellow» в этот массив. Может быть заманчиво сделать это:

    this.state.colors.push('yellow')
    


    Или даже это:

    this.state.colors = [...this.state.colors, 'yellow']
    


    Но оба эти подхода неверны! При обновлении состояния в компоненте класса вам всегда нужно использовать метод setState, и вы всегда должны быть осторожны, чтобы не изменять объекты. Вот правильный способ добавить элемент в массив:

    this.setState(prevState => ({ colors: [...prevState.colors, 'yellow'] }))
    


    И это приводит нас прямо к ошибке номер два.

  3. Установка состояния, которое опирается на предыдущее состояние без использования функции

  4. Есть два способа использовать метод setState.

    Первый способ - предоставить объект в качестве аргумента.

    Второй способ - предоставить функцию в качестве аргумента.

    Итак, когда вы хотите использовать один поверх другого?

    Если бы у вас была, например, кнопка, которую можно включить или отключить, у вас может быть элемент состояния под названием isDisabled, который содержит логическое значение. Если вы хотите переключить кнопку с включенного на отключенное, может возникнуть соблазн написать что-то вроде этого, используя объект в качестве аргумента:

    this.setState({ isDisabled: !this.state.isDisabled })
    


    Итак, что с этим не так? Проблема заключается в том, что обновления состояния React могут быть пакетными, а это означает, что в одном цикле обновления может происходить несколько обновлений состояния. Если ваши обновления должны были быть пакетными, и у вас было несколько обновлений до включенного / отключенного состояния, конечный результат может быть не тем, что вы ожидаете.

    Более правильным способом обновления состояния здесь было бы предоставление функции предыдущего состояния в качестве аргумента:

    this.setState(prevState => ({ isDisabled: !prevState.isDisabled }))
    


    Теперь, даже если обновления вашего состояния являются пакетными, и несколько обновлений в состоянии включенного / выключенного состояния выполняются вместе, каждое обновление будет полагаться на правильное предыдущее состояние, чтобы вы всегда получали результат, который ожидали.

    То же самое верно для чего-то вроде увеличения счетчика.

    Не делайте этого!!!:

    this.setState({ counterValue: this.state.counterValue + 1 })
    


    Делайте правильно!!!:

    this.setState(prevState => ({ counterValue: prevState.counterValue + 1 }))
    


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


  5. Не забывайте, что setState является асинхронным

  6. Наконец, важно помнить, что setState является асинхронным методом. В качестве примера, давайте представим, что у нас есть компонент с состоянием, которое выглядит так:

    this.state = { name: 'John' }
    


    И затем у нас есть метод, который обновляет состояние и затем выводит состояние на консоль:

    this.setState({ name: 'Matt' })
    console.log(this.state.name)
    


    Вы можете подумать, что вывод будет 'Matt' на консоль, но это не так! Это будет - «Джон»!

    Причина этого в том, что опять же setState является асинхронным. Это означает, что он собирается запустить обновление состояния, когда доберется до строки, которая вызывает setState, но код ниже будет продолжать выполняться, поскольку асинхронный код не является блокирующим.

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

    Правильный способ записать текущее состояние после обновления:

    this.setState({ name: 'Matt' }, () => console.log(this.state.name))
    


    Намного лучше! Теперь вывод в консоль будет 'Matt', как и ожидалось.
Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook.


Удачного кодирования!

Оригинал можно посмотреть здесь: Tyler Hawkins                                                                                                                                                              

Телеграм канал - Full Stack JavaScript Developer
Помочь проекту (любая валюта). DONATE

воскресенье, 14 июня 2020 г.

Кастомизация темы VSCode.

Кастомизация — индивидуализация продукции под заказы конкретных потребителей путём внесения конструктивных или дизайнерских изменений.



Сегодня я хочу вам рассказать об очень простой штуке, которая во многом, я уверен, облегчит жизнь всем тем, кто работает в редакторе VSCode. Речь пойдет о некоторых возможностях кастомизировать (настроить для ваших нужд и вкусов) тему самого редактора.

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

Подумал, что было бы здорово, если бы можно было отличать их по визуальным признакам. Например - какой-либо особенный цвет верхней панели, или еще что-нибудь. Потом захотелось менять всю тему от проекта, к проекту, говорят, что это способствует лучшей усидчивости и откладывает "выгорание" на долгий срок. Короче говоря, приступаем.

Погнали!
  1. Открываем редактор VSCode. Идем в настройки. Ctrl + +, или по длинному пути - нажимаем внизу, слева - шестеренку и выбираем "Параметры"




  2. В строке поиска (сверху) забиваем - title и нас сразу перекинет в нужную часть настроек. Там опускаемся чуть ниже и ищем такие строки:
    "Window: Title Bar Style
    Вы можете настроить внешний вид заголовка окна. В Linux и Windows этот параметр также влияет на внешний вид меню приложения и контекстного меню. Для применения изменений требуется полная перезагрузка."
    В выпадающем списке выбираем пункт - Custom. VSCode - редактор, сообщит, что изменения вступят в силу сразу после перезагрузки редактора




  3. Теперь остается только добавить нужные изменения, чтобы редактор VSCode их отобразил. Для этого, если вы вносите изменения в готовый проект, то ищите в нем папку .vscode, а в ней файл settings.json. Если проект новый, или хотите выделить какую-то отдельную папку, то нужно создать эту папку и в ней файл. У меня в нем уже были прописаны пара моих настроек (автосохранение и размер шрифта) и сразу после них, добавим строки отвечающие за цвет шрифта и окраску верхней панели


  4. settings.json
    {
       "files.autoSave": "onWindowChange",
       "editor.fontSize": 16,
       "workbench.colorCustomizations": {
           "titleBar.activeForeground": "#000",
           "titleBar.inactiveForeground": "#000000CC",
           "titleBar.activeBackground": "#51ff00",
           "titleBar.inactiveBackground": "#51ff00cc",
       }
    }
    


    Не забывайте добавить запятую, перед вставкой вашего куска кода!

    Как вы можете легко понять из названий свойств, то мы поменяли только верхнюю панель (title).

    Ctrl + S - сохраняем, чтобы изменения вступили в силу.



Если вы хотите внести дополнительные изменения в саму тему именно этого проекта, то можете добавить еще некоторые настройки. Например:

settings.json
{
  "files.autoSave": "onWindowChange",
  "editor.fontSize": 16,
  "workbench.colorCustomizations": {
    "titleBar.activeForeground": "#000",
    "titleBar.inactiveForeground": "#000000CC",
    "titleBar.activeBackground": "#51ff00",
    "titleBar.inactiveBackground": "#51ff00cc",
    "editorGroupHeader.tabsBackground": "#1d262a",
    "editorWhitespace.foreground": "#263238", // theme background
    "background": "#FF00FF",
    "badge.foreground": "#B4B4B4",
    "panel.border": "#1d262a",
    "sideBar.foreground": "#B4B4B4",
    "sideBar.background": "#1d262a",
    "statusBar.background": "#1d262a",
    "tab.border": "#546e7a",
    "tab.inactiveForeground": "#B4B4B4",
    "tab.inactiveBackground": "#1d262a"
  }
}


Общий вид темы будет таким:



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

Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook.


Удачного кодирования!                                                                                                                                                              

Телеграм канал - Full Stack JavaScript Developer
Помочь проекту (любая валюта). DONATE

четверг, 28 мая 2020 г.

React. Как использовать «useContext» в React Hooks

Следующая статья посвящена пониманию работы хуков «useContext» в компонентах React.



Хук «useContext» используется для создания общих данных, к которым можно обращаться по всей иерархии компонентов, не пропуская реквизиты - props вручную до каждого уровня. Определенный контекст будет доступен для всех дочерних компонентов без использования props.

Ниже приводится цитата о контексте с официальной веб-страницы React:

Контекст позволяет передавать данные через дерево компонентов без необходимости передавать пропсы на промежуточных уровнях.

В типичном React-приложении данные передаются сверху вниз (от родителя к дочернему компоненту) с помощью пропсов. Однако, этот способ может быть чересчур громоздким для некоторых типов пропсов (например, выбранный язык, UI-тема), которые необходимо передавать во многие компоненты в приложении. Контекст предоставляет способ делиться такими данными между компонентами без необходимости явно передавать пропсы через каждый уровень дерева.


В статье ниже мы сосредоточимся на том, как «useContext» работает программно. Но прежде чем начать с «useContext», давайте сначала разберемся, как сделать данные доступными от родительских к дочерним компонентам, используя атрибуты «props». Затем мы введем хук «useContext» для компонента, чтобы понять его влияние.

Передача данных в дочерние компоненты без «useContext»

Ниже приведено описание создания родительского компонента, содержащего сведения о конкретном сотруднике. Добавленные сведения о сотруднике не используются в родительском компоненте, но могут использоваться некоторыми дочерними компонентами, которые мы расскажем чуть позже. Но давайте сначала посмотрим на реализацию родительского компонента.

import React, { useState } from "react";

function UserDetailsComponent() {
  var [userDetails, setUserDetails] = useState({
    name: "Yaroslav",
    age: 50
  });
                                               
  return (
    <div>
      <h1>This is the Parent Component</h1>
    </div>                                         
  )
}


Теперь давайте введем еще два компонента в иерархию, мы добавим к иерархии «ChildComponent», который по-прежнему не будет получать доступ к данным, доступным из родительского компонента. ChildComponent должен далее передать эти данные своему дочернему компоненту «SubChildComponent», где данные, наконец, отображаются.

Расширяя код далее, мы отправим переменную состояния далее в дочерний компонент «ChildComponent» с помощью «props», который отправит эти данные дальше в его дочерний компонент «SubChildComponent». Давайте посмотрим на код ниже, чтобы объяснить дальнейшие сценарии.

import React, { useState } from "react";

function UserDetailsComponent() {
  var [userDetails, setUserDetails] = useState({
    name: "Yaroslav",
    age: 50,
  });

  return (
    <div>
      <h1>This is the Parent Component</h1>
      <hr />
      <ChildComponent userDetails={userDetails}></ChildComponent>
    </div>
  );
}

function ChildComponent(props) {
  return (
    <div>
      <h2>This is Child Component</h2>
      <hr />
      <SubChildComponent userDetails={props.userDetails}></SubChildComponent>
    </div>
  );
}

function SubChildComponent(props) {
  return (
    <div>
      <h3>This is Sub Child Component</h3>
      <h4>User Name: {props.userDetails.name}</h4>
      <h4>User Age: {props.userDetails.age}</h4>
    </div>
  );
}



В приведенном выше коде родительский компонент определяет некоторые переменные состояния, которые не используются внутри компонента, вместо этого он отправляется далее дочернему компоненту «ChildComponent» в качестве данных «props». «ChildComponent» не использует «userDetails» и далее отправляет данные своему дочернему компоненту «SubChildComponent» в качестве «propsх» данных. Этот «SubChildComponent» использует данные, переданные ему как «props», и отображает имя пользователя и возраст в компоненте.

Вы можете поиграть с вышеуказанным кодом в следующем онлайн-редакторе: Code Sandbox link

Проблема с вышеуказанным кодом

Я бы попытался объяснить проблему с приведенным выше кодом, указав приведенные ниже утверждения. Надеюсь, это будет иметь смысл для вас.
  1. Данные состояния определяются на верхнем уровне, определенные данные передаются дочернему компоненту, где данные больше не используются. Данные от родителя передаются как «props» данные. Эти «props» данные не влияют на дочерний компонент, но, тем не менее, дочерний компонент должен поддерживать данные «props».
  2. «ChildComponent» далее передает эти «props» данные «SubChildComponent». «ChildComponent» здесь просто идут издержки на управление «props» из родительского компонента, только для того, чтобы сделать его доступным для других дочерних компонентов.
  3. Нам необходимо явно передавать «props» даже тем компонентам, которые даже не используют его только для того, чтобы сделать данные доступными для иерархии ниже. Мы поддерживаем постоянную передачу данных «props» по всей иерархии приложения.
Я надеюсь, что вы сможете решить проблему с передачей «props» по всей иерархии приложения. 😉

«UseContext» для спасения…

Чтобы решить вышеупомянутую проблему передачи «props» данных даже тем компонентам, которые не требуют этого только потому, что данные требуются в дальнейшей иерархии, мы можем использовать «Context API».

«Context API» позволяет нам определять контекстный объект, который хранит некоторые данные и сделает его доступным по всей иерархии, не передавая данные как «props». Для упрощения, контекст предоставляет контейнер, содержащий некоторые данные и делающий его доступным для всей иерархии компонентов ниже.

Давайте воссоздадим приведенный выше пример с «Context API» и увидим разницу.

Чтобы достичь этого, мы сначала создадим объект контекста. После того, как объект создан с использованием React.createContext. Затем мы будем использовать этот объект контекста в компоненте верхнего уровня и добавим данные, необходимые для всей иерархии. UserDetailContext.Provider используется для предоставления значения созданному объекту контекста. Объект, который необходимо добавить, предоставляется атрибуту value.

import React, { useState } from "react";

var userDetailContext = React.createContext(null);

export default function UserDetailsComponent() {
  var [userDetails] = useState({
    name: "Mayank",
    age: 30
  });

  return (
    <userDetailContext.Provider value={userDetails}>
      <h1>This is the Parent Component</h1>
      <hr />
      <ChildComponent userDetails={userDetails} />
    </userDetailContext.Provider>
  );
}


В приведенном выше коде мы создали объект контекста userDetailsContext и добавляем данные о состоянии в контекст в UserDetailsComponent. Поскольку данные добавляются в контекст, предоставленный в этом компоненте, любой компонент в иерархии будет иметь доступ к данным контекста.

Далее, мы хотим, чтобы данные получали доступ через SubChildComponent, не передавая их как «props» данные. Чтобы получить доступ к данным в SubChildComponent, нам нужно получить доступ к контексту, созданному ранее на верхнем уровне, и получить доступ к данным, доступным в этом контексте.

К контекстным данным, добавленным сверху, можно получить доступ через SubChildComponent, используя ключевое слово useContext

React.useContext(userDetailContext);

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

import React, { useState } from "react";

var userDetailContext = React.createContext(null);

export default function UserDetailsComponent() {
  var [userDetails] = useState({
    name: "Yaroslav",
    age: 50,
  });

  return (
    <userDetailContext.Provider value={userDetails}>
      <h1>This is the Parent Component</h1>
      <hr />
      <ChildComponent userDetails={userDetails} />
    </userDetailContext.Provider>
  );
}

function ChildComponent(props) {
  return (
    <div>
      <h2>This is Child Component</h2>
      <hr />
      <SubChildComponent />
    </div>
  );
}

function SubChildComponent(props) {
  var contextData = React.useContext(userDetailContext);
  return (
    <div>
      <h3>This is Sub Child Component</h3>
      <h4>User Name: {contextData.name}</h4>
      <h4>User Age: {contextData.age}</h4>
    </div>
  );
}



В приведенном выше примере мы видим, что ключевое слово useContext сделает данные родительского компонента доступными для дочерних компонентов на любом уровне в иерархии, не раскрывая их как «props» данные. Вы можете играть с кодом в следующем онлайн-редакторе ... Code Sandbox link

Использование

Считается, что связка двух хуков - useContext + useReducer(о нем я расскажу в следующий раз) может полностью заменить Redux! Мнения "за":
  • Вы можете использовать хуки (useContext + useReducer) вместо Redux в не больших приложениях (где нет необходимости в больших комбинированных Reducers). В данном случае Redux действительно может оказаться избыточным.
Мнения "против":
  • Большое количество кода уже написано на связке React + Redux и переписывать его на хуки (useContext + useReducer) кажется мне не целесообразным, по крайней мере сейчас.
  • Redux — проверенная библиотека, хуки — нововведение, их интерфейсы и поведение может измениться в дальнейшем.
  • Для того чтобы сделать использование useContext + useReducer действительно удобным, придется написать некоторые велосипеды.
Выводы делайте сами, а мой ниже...😉

Вывод

«UseContext» - это удивительный способ избавиться от издержек, связанных с передачей данных через props на разные уровни иерархии, даже если это не требуется.

Попробуйте поработать с React Hooks некоторое время и эти интересные функции, которые заставят вас задуматься о функциональном программировании.

Хотите оставаться в курсе новинок в области JS-программирования? Подписывайтесь на мой канал, вступайте в группу на Facebook. Если понравившаяся статья оказалась еще и полезной, то буду благодарен вашим пожертвованиям на развитие сайта - кнопка DONATE ниже (любая валюта).

Удачного кодирования!                                                                                                                                                              

Телеграм канал - Full Stack JavaScript Developer
Помочь проекту (любая валюта). DONATE

среда, 27 мая 2020 г.

React . Детальный обзор Context API

React Context API предоставляют механизм для передачи данных через дерево компонентов без передачи реквизитов на каждый уровень вручную.



Нам не нужно передавать данные на каждый уровень, вместо этого мы создаем контекст для компонента более высокого уровня и делаем данные контекста доступными для дочерних или дочерних компонентов. Статья посвящена подробному пониманию концепций React Context.

Друзья, я ранее уже много раз рассказывал вам об использовании реакт-хуков для быстрого, удобного и простого построения ваших приложений. Если вы что-то подзабыли, то welcome к моим постам по - React. Там вы найдете много простых и интересных решений, в частности - полноценное приложение построенное только на функциональных компонентах и реакт-хуках. Стоит посмотреть построение React-Сайта и некоторые мои статьи и переводы на gitHub Там я много пишу о самых распространенных и не очень решениях для построений реакт-приложений.


Когда нужно использовать React Context

В этом разделе мы увидим, когда нам нужно использовать React Context API. API React Context просты в использовании и очень эффективны. Приложение React может состоять из иерархии Компонентов, имеющих отношение Parent-Child, иерархия может иметь несколько уровней.

Предположим, что наше приложение содержит компонент на верхнем уровне, содержащий некоторые данные, которые должны использоваться компонентом на нижнем уровне. Компоненты содержатся в древовидной структуре, где один из компонентов является родительским компонентом, а другие компоненты представляют дочерние компоненты, эти дочерние компоненты могут иметь дополнительные дочерние компоненты, представляющие древовидную структуру.



Пример кода:

import React from "react";

export default class GrandParents extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      surName: "Gupta",
    };
  }
  render() {
    return (
      <>
        <h1>This is the Grand Parent Component</h1>
        <Parents surName={this.state.surName} />
      </>
    );
  }
}
function Parents(props) {
  return (
    <div>
      <h2>This is a Parent Component</h2>
      <Children surName={props.surName} />
    </div>
  );
}
function Children(props) {
  return (
    <div>
      <b>Inherited Child Properties from Grand Parents: </b>
      <label>{props.surName}</label>
    </div>
  );
}



Code Sandbox link

В приведенном выше примере у нас есть компонент верхнего уровня «GrandParent», который содержит некоторую строку данных «surName». Этот компонент содержит другой компонент «Parent», которому мы отправляем эту информацию о «surName» в данных «props». Этот «родительский - Parent» компонент не использует эти данные, ему просто нужно передать эти данные следующему дочернему компоненту «Children», а затем этот компонент «Children» использует эту информацию «surName».

Проблема с вышеуказанным кодом

В приведенном выше сценарии данные требуются только на дочернем уровне. Но мы распространяем данные по всей Иерархии, чтобы сделать их доступными на более низком уровне («Children»). На первый взгляд ничего особенного, но представьте, что на месте одного родительского компонента, который просто передает пропсы ниже, не один а десять, а то и двадцать уровней компонентов? Используя контекст, мы можем сократить издержки на передачу данных по всей иерархии, чтобы сделать их доступными для компонентов самого низкого уровня. Далее давайте рассмотрим детали того, как уменьшить издержки на передачу props с помощью React Context.

Работа с контекстом React - React Context

Чтобы решить вышеуказанную проблему, мы можем использовать API React Context.React Context API состоит из:
  1. Context Object

    Чтобы использовать Context в приложении, нам сначала нужно создать объект контекста - Context Object, который способен хранить данные для приложения. Этот объект можно сделать доступным для иерархии для подачи или получения данных. Приведенный ниже код позволит нам создать объект контекста для всей иерархии.

    const FamilyContext = React.createContext({});


  2. Context Provider

    const FamilyProvider = FamilyContext.Provider;

    Context Provider используется для предоставления значения этому объекту контекста - Context Object. Мы можем добавить к контексту, используя этот объект Context Provider.


  3. Context Consumer

    const FamilyConsumer = FamilyContext.Consumer;

    Этот объект потребителя - Context Consumer используется для получения значения контекста и предоставления значения для компонента. Значение, сохраненное в контексте с использованием «Context Provider», может быть получено с помощью объекта Consumer Context.

    Давайте попробуем увидеть полностью реализованный код для того же сценария.


import React from "react";
const FamilyContext = React.createContext({});
export const FamilyProvider = FamilyContext.Provider;
export const FamilyConsumer = FamilyContext.Consumer;

export default class GrandParents extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      surName: "Kolesnikov",
      random: "Text",
    };
  }
  render() {
    return (
      <FamilyContext.Provider value={this.state}>
        <div>
          <h1>Grand Parents Initial Surname: </h1>
          {this.state.surName}
        </div>
        <Parents></Parents>
      </FamilyContext.Provider>
    );
  }
}

function Parents(props) {
  return (
    <div>
      <h2>Inherited Parent Property With "props":</h2>
      <label></label>
      <br />
      <br />
      <br />
      <Children />
    </div>
  );
}

class Children extends React.Component {
  render() {
    return (
      <FamilyConsumer>
        {(context) => {
          return (
            <div>
              <h3>Inherited Child Properties without "props": </h3>
              <label>{context.surName}</label>
            </div>
          );
        }}
      </FamilyConsumer>
    );
  }
}




Code Sandbox link

В приведенном выше коде следует обратить внимание на следующее:

  1. Сверху мы создали Объект контекста (FamilyContext), Объект провайдера (FamilyProvider) и Объект потребителя (FamilyConsumer).
  2. Значение добавляется в контекст в компоненте «GrandParent» с использованием объекта «Провайдер» - Provider Object. Мы используем свойство value для добавления необходимых данных в объект провайдера -Provider Object. Данные не нужно использовать в компоненте «Родитель» - Parent.
  3. Чтобы сделать данные напрямую доступными для компонента Children, мы используем Consumer Object - объект-потребитель (FamilyConsumer). Это сделает данные доступными непосредственно дочерним компонентам.
А если в двух словах, то мы просто взяли от реакта нужные нам части контекста и определили их в самом верху файла:

const FamilyContext = React.createContext({});
export const FamilyProvider = FamilyContext.Provider;
export const FamilyConsumer = FamilyContext.Consumer;


Затем, просто обернули все, что рендерим в корневом компоненте в провайдер, в который и передали пропсы, а в нужном месте (Дочерний компонент) достали их из контекста через функцию.

Все это в коде выделил красным!

PS

В приведенном выше примере данные не нужно передавать по всей иерархии, данные были доступны на верхнем уровне и были непосредственно доступны дочернему элементу с помощью объекта контекста. Отсюда устраняется необходимость передачи данных с использованием «реквизита - props» по всей иерархии.

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

React. Как использовать «useContext» в React Hooks

Хотите оставаться в курсе новинок в области JS-программирования? Подписывайтесь на мой канал, вступайте в группу на Facebook. Если понравившаяся статья оказалась еще и полезной, то буду благодарен вашим пожертвованиям на развитие сайта - кнопка DONATE ниже (любая валюта).

Удачного кодирования!                                                                                                                                                              

Телеграм канал - Full Stack JavaScript Developer
Помочь проекту (любая валюта). DONATE

воскресенье, 26 апреля 2020 г.

Callback functions в JavaScript.

В этой статье мы познакомимся с функциями обратного вызова в JavaScript на нескольких примерах. Функции обратного вызова также называют функциями высшего порядка.



Функция высшего порядка — это функция, которая может принимать другую функцию в качестве аргумента или возвращать другую функцию в качестве результата.

Функция в JS является объектом первого класса.

В языках программирования существует понятие "объекты первого рода (или класса)". Им обозначают элементы, которые могут быть переданы в функции, возвращены из функций и присвоены переменным (или константам). К таким элементам относятся любые данные, например числа, строки, массивы или логические значения. Обратите внимание, что сама переменная (или константа) под это понятие не попадает, объектом первого рода считаются те данные, которые лежат в переменной (или константе).

  1. Мы можем передать объект в функцию в качестве аргумента.
  2. Мы также можем передать другие функции в функцию в качестве аргумента для выполнения в некоторый момент.


Простой пример для понимания:



    let function1 = function(){
        console.log("I'm the function1 result");
    }
    
    
    let function2 = function(callback){
        console.log("I'm the function2 result");
        
        callback();
    }
    
    
    function2(function1);

// I'm the function2 result
// I'm the function1 result


Всё это работает нормально. Легко понять, как передать функцию в качестве аргумента другой функции.

Но зачем нам этот обратный вызов в JavaScript?

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

 let calculate = function(x, y, operation){
      
      if(operation === 'subtract')
          return x - y;
    
      else if(operation === 'divide')
          return x/y;
  }
  
  console.log(calculate(10,3,'subtract'));


 // Output:
 //  7


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

Теперь для всех возможных типов вычислений, эта библиотека должна реализовать все это. Мы можем передать add, кратно или это могут быть случайные операции. Но эта библиотека поддерживает только два типа вычислений: вычитание и деление.

Так что делать? какой лучший способ для этого?

Лучший способ сделать это - сделать функцию как можно более абстрактной. Чтобы сделать функцию абстрактной, нам нужно вывести функциональность наружу. Функция должна быть общей.

Посмотрите на приведенный ниже пример, чтобы лучше понять.

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

let add = function (x, y) {
  return x + y;
};

let substract = function (x, y) {
  return x - y;
};

let multiplay = function (x, y) {
  return x * y;
};

let divide = function (x, y) {
  return x / y;
};

let calculate = function (x, y, callback) {
  if (typeof callback === "function") return callback(x, y);
};

console.log(calculate(12, 8, add));
// 20


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

Я также могу сделать это,

let calculate = function (x, y, callback) {
  if (typeof callback === "function") return callback(x, y);
};

console.log(
  calculate(12, 8, function (x, y) {
    return x >= y;
  })
);
// true


Исходя из моих требований, я могу изменить все, что смогу. Этот пример выше возвращает true.

Пример из реальной жизни:

Одним из примеров функции обратного вызова JavaScript в реальном времени является метод sort().

var simpleArray = [
  {
    key: 12,
    value: "Hello",
  },
  {
    key: 13,
    value: "World",
  },
  {
    key: 14,
    value: "Something",
  },
];

simpleArray.sort(function (val_1, val_2) {
  if (val_1.key < val_2.key) {
    return -1;
  } else {
    return 1;
  }
});

let result = simpleArray.forEach((res) =>
  console.log(res.key + " " + res.value)
);
// 12 Hello
// 13 World
// 14 Something


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

Давайте изменим функцию обратного вызова для сортировки массива по ключам в порядке убывания.

simpleArray.sort(function (val_1, val_2) {
  if (val_1.key > val_2.key) {
    return -1;
  } else {
    return 1;
  }
});

let result = simpleArray.forEach((res) =>
  console.log(res.key + " " + res.value)
);
// 14 Something
// 13 World
// 12 Hello


Давайте изменим функцию обратного вызова для сортировки массива на основе значений в порядке возрастания.

simpleArray.sort(function (val_1, val_2) {
  if (val_1.value < val_2.value) {
    return -1;
  } else {
    return 1;
  }
});
// 12 Hello
// 14 Something
// 13 World


Давайте изменим функцию обратного вызова для сортировки массива по значениям в порядке убывания.

simpleArray.sort(function (val_1, val_2) {
  if (val_1.value > val_2.value) {
    return -1;
  } else {
    return 1;
  }
});
// 13 World
// 14 Something
// 12 Hello


Приведенные выше примеры, помогают не только понять работу обратных вызовов в JavaScript, но помогают написать некоторые функции сортировки, а это в свою очередь полезно тем, что не нужно "тянуть" в проект всю библиотеку (например Lodash), только ради простой сортировки.

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

Таким образом, вы можете сами написать для своих проектов свою собственную библиотеку и использовать ее в виде подключаемого модуля. Как это сделать? Смотрите мои статьи в этом блоге в разделе

JAVASCRIPT&PHP                                                                                                                                                              

Телеграм канал - Full Stack JavaScript Developer

пятница, 1 ноября 2019 г.

Git - работа с репо без пароля.

Если вы уже достаточно освоили работу с системой контроля версий Git и вас уже стало напрягать постоянное введение имени пользователя и пароля, то пришло время решить и эту проблему. Сегодня мы научимся работать с репо по ssh-соединению.




Создание нового ssh-ключа и добавление ssh-agent достаточно хорошо и понятно расписано на самом GitHub и трудностей здесь возникнуть не должно. Поэтому я не буду на этом останавливаться. Рассмотрим некоторые более сложные вопросы, которые могут возникнуть.

Тема актуальна для пользователей Windows и Git-Bash оболочки.

Для начала стоит проверить существуют ли уже у вас ключи в вашем Git. Для этого вам нужно открыть Git Bash и ввести команду:

$ ls -al ~/.ssh
# Команда покажет файлы в вашем каталоге .ssh, если они существуют


Если вы увидите что-то похожее на файлы с такими расширениями, значит ключи уже есть.
id_dsa.pub
id_ecdsa.pub
id_ed25519.pub
id_rsa.pub
В этом случае, нам остается их скопировать и вставить в настройки аккаунта на GitHub.

Для копирования в буфер обмена вводим команду:

$ clip < ~/.ssh/id_rsa.pub
# Копирует содержимое файла id_rsa.pub в буфер обмена


Идем в настройки вашего аккаунта:



На боковой панели настроек пользователя нажмите клавиши SSH и GPG.



Выбираем New SSH key or Add SSH key.



В поле «Title» добавьте описательную метку для нового ключа. Например, если вы используете персональный ключ, вы можете назвать этот ключ «Personal Windows Air».

Вставьте свой ключ в поле «Key».



Нажмите кнопку добавить - Add SSH key.



Далее будет предложено, подтвердите свой пароль GitHub.



Идем в корневую директорию вашего Git

$ cd ~


В ней нам нужно создать файл .profile с настройками:

$ echo '' >> .profile #создаем пустой файл .profile


Открываем его в любом редакторе и вставляем в него:


env=~/.ssh/agent.env

agent_load_env () { test -f "$env" && . "$env" >| /dev/null ; }

agent_start () {
    (umask 077; ssh-agent >| "$env")
    . "$env" >| /dev/null ; }

agent_load_env

# agent_run_state: 0=agent running w/ key; 1=agent w/o key; 2= agent not running
agent_run_state=$(ssh-add -l >| /dev/null 2>&1; echo $?)

if [ ! "$SSH_AUTH_SOCK" ] || [ $agent_run_state = 2 ]; then
    agent_start
    ssh-add
elif [ "$SSH_AUTH_SOCK" ] && [ $agent_run_state = 1 ]; then
    ssh-add
fi

unset env


Если все прошло успешно, то вы все сделали правильно и теперь у вас есть возможность использовать ssh-доступ к вашим репо. Если же, у вас уже не только существует, но и используется (возможно для отдельно взятого репо) ключ, то вы получите предупреждение розовым цветом вверху страницы.

Error: Key already in use


Для решения этой проблемы, нам нужно найти, где используется (в каком из репо) ключ и удалить его.

Здесь все проще простого. Вводим в Bash

$ ssh -T -ai ~/.ssh/id_rsa git@github.com
# Подключитесь к GitHub используя определенный ключ ssh
> Hi username! You've successfully authenticated, but GitHub does not
> provide shell access.


Имя пользователя в ответе - это учетная запись GitHub, к которой в данный момент подключен ключ. Если ответ выглядит как «username / repo», ключ был прикреплен к хранилищу в качестве ключа развертывания.

Идете в это репо и в настройках удаляете ключ.

Если вы все сделали правильно, значит теперь вы сможете получать доступ к репо по ssh-соединению. Для работы со старыми репо, которые установлены у вас на машине, вам стоит переподключить их. Это делается достаточно просто.

Допустим, что я решил поработать с каким-то проектом. Для того, чтобы узнать его репо на gitHub мне достаточно, находясь в папке проекта, ввести в гит следующую команду.

git remote -v


Открыть git-Bash в нужной папке - правая кнопка мыши в нужной папке и выбрать Открыть Git Bash Here



Если ваш репо связан по http- протоколу, то для того, чтобы его переключить на ssh нам нужно, находясь в нужной папке на локальном машине ввести в git-bash следующее.

git remote set-url origin git@github.com:username/reponame.git


Вместо выделенного желтым - git@github.com:username/reponame.git в примере сверху, вам нужно вставить ссылку на ssh-соединение вашего репо. Её вы можете взять на gitHub вашего репо, нажав на кнопку Clone or download. Выбрать - Use SSH и скопировать ссылку (подчеркнуто на фото).



Таким простым способом, мы с вами получили доступ по SSH протоколу к нашему GitHub - репо.

Если эта тема для вас интересна, то я могу вам рассказать, как работать с несколькими аккаунтами с одной машины.

Пишите в комментариях, кодируйте и добивайтесь успехов!

Материалы по Git, которые могут быть вам интересны:


Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook.


Удачного кодирования!                                                                                                                                                              

Телеграм канал - Full Stack JavaScript Developer
Помочь проекту (любая валюта). DONATE

вторник, 1 октября 2019 г.

Node.js - Переименование файлов.

Сегодня мы познакомимся с файловой системой Node.js, а именно с массовым переименованием файлов в определенной папке (директории)



Ранее, я много писал о работе с Node.js. Если вы что-то пропустили, то посмотрите в разделе "Карта сайта". Можете воспользоваться поиском по сайту, или выбрать посты о Node.js по ярлыку. Можете просто пройти по ссылке в начале абзаца на оглавление сайта, а именно к разделу о Node.js.

Самый надежный способ получать знание это написать что-то полезное! Сегодня, я предлагаю написать простой скрипт, который будет брать некоторые фото (image.jpg) и менять их название на что-то более-менее вразумительное нежели бессвязный набор символов.

Например: У меня на компьютере есть некая папка "srcImage", в которой лежат файлы с разнообразными именами, которые мы хотим изменить. Переименованные файлы мы будем сохранять или в этой же папке, или в любой другой папке (директории).

В Node.js есть встроенный модуль - fs - File System, который предоставляет нам такую ( и множество других) полезную возможность. Мы им и воспользуемся.

Если посмотреть документацию, то там все очень очень просто:

fs.rename('/tmp/hello', '/tmp/world', (err) => {
  if (err) throw err;
  console.log('renamed complete');
});


Обязательно посмотрите в этом блоге -Как правильно задать путь к файлу. Это значительно облегчит вашу жизнь в дальнейшем!
В приведенном примере из документации, все очень просто:

/tmp/hello - относительный путь к папке в которой нужно переименовать файлы и сам файл.

/tmp/world - относительный путь к папке в которую нужно положить переименованный файл и сам файл.

Если будет ошибка, то отследить её в консоли, а если успех, то вывести сообщение, что все прошло успешно.

Нашу задачу мы разобьем на такие подзадачи:
  1. Выбрать шаблон для переименования - придания однотипности новым именам файла.
  2. Получить последовательный доступ к файлам, которые лежат в определенной директории для переименования.
  3. Изменить значение каждого файла на удобное.
  4. Отправить файлы в нужную папку.
  5. Поймать ошибку в случае неудачи или подтверждение - в случае успеха.


Выбрать шаблон для переименования

Вы можете сделать это по собственному усмотрению. Например - задать его из определенного количества случайных цифр и букв ( но тогда он ничем не будет отличаться от исходных :-) ) Или задать некое строковое значение. Например: "My_favorite_file", "vacation" и т.д.

Я решил использовать дату в формате дд-мм-гг (01-10-2019). К дате мы будем добавлять порядковый номер файла в папке и некое префиксное значение. Его я добавил, потому что я часто перемещаю файлы в различные папки и мне удобно знать изначальное место хранения данного файла.

Итак, приступаем. Создадим файл, например rename.js

Первым делом импортируем в него нужный нам модуль:const fs = require("fs");

Получим дату в нужном формате и выведем её в консоль:

const fs = require("fs");

var d = new Date();
var curr_date = d.getDate();
var curr_month = d.getMonth() + 1;
var curr_year = d.getFullYear();

var data_f = curr_date + "-" + curr_month + "-" + curr_year;
console.log(data_f);
// 1-10-2019


  1. Если вы работаете, как и я в VS-Code, то сделать это очень просто нажатием клавиш Ctrl + Shift + Ё `(открыть консоль) и запустить код - Ctrl + Alt + N (с расширением code runner) или другим способом.

  2. Посмотреть список установленных расширений - просто введите в консоль code --list-extensions и нажмите Enter

  3. Проще всего запустить файл из Node.js - находясь в нужной директории, набрать в консоли node и имя_файла. В нашем случае это node rename. Именно так мы и будем делать, потому как наш скрипт будет работать на Node.js.

Получить последовательный доступ к файлам

Для того, чтобы получить каждый отдельный файл в папке (srcImage) , мы воспользуемся встроенным методом fs.readdir. По ссылке, вы можете прочитать официальную документацию.

Для того, чтобы этот метод сработал правильно, мы должны передать в него первым аргументом - путь к файлам, а вторым - функцию обратного вызова (callback-function) в которую первым аргументом передадим ошибку - err, а вторым полученные файлы, который и выведем в консоль методом forEach, в который дополнительно передадим порядковый номер файла - i. В консоли покажем каждый файл с соответствующим ему порядковым номером i

const fs = require("fs");
const srcFolder = "C:/Users/Branch/Node/abc-rename-file/srcImage/";
var d = new Date();
var curr_date = d.getDate();
var curr_month = d.getMonth() + 1;
var curr_year = d.getFullYear();

var data_f = curr_date + "-" + curr_month + "-" + curr_year;

fs.readdir(srcFolder, (err, files) => {
  files.forEach((file, i) => {
    console.log(`${file} i=${i}`);   
  });
});



В переменную srcFolder нам следует поместить относительный, но лучше (для будущего использования) абсолютный путь к файлу в виде строкового значения.

запускаем наш код :

node rename


И теперь в консоли мы увидим все файлы из папки с порядковыми номерами.



Изменить значение каждого файла.

Для наглядности, я создам папку, куда мы будем перемещать переименованные файлы в другой директории и назову ее outImage. В наш код помещу абсолютный путь к ней в переменную outFolder:

const outFolder = "C:/Users/Euroset/GoogleD/outFolder/";

Как я говорил ранее, я создам дополнительно свой префикс, который добавлю к дате, полученной ранее:

var myPrefix = "y";
var prefix = myPrefix + data_f;


Сейчас, нам остается воспользоваться встроенным методом для переименования файлов, о котором я говорил ранее и добавить к имени наш префикс и порядковый номер, ну и конечно не забыть поймать ошибку, если есть или вывести сообщение об успехе:

fs.rename(srcFolder + file, outFolder + i + prefix + ".jpg", err => {
      if (err) throw err;
      console.log("rename completed!");
    });



запускаем наш код :

node rename


В консоль получим многократный вывод сообщения об успешном завершении операции. Папка srcImage пуста, а в новой папке outFolder появились переименованные соответствующим образом файлы:



rename полностью:
const fs = require("fs");
const srcFolder = "C:/Users/Branch/Node/abc-rename-file/srcImage/";
const outFolder = "C:/Users/GoogleD/outFolder/";

var d = new Date();
var curr_date = d.getDate();
var curr_month = d.getMonth() + 1;
var curr_year = d.getFullYear();

var data_f = curr_date + "-" + curr_month + "-" + curr_year;
var myPrefix = "y";
var prefix = myPrefix + data_f;

fs.readdir(srcFolder, (err, files) => {
  files.forEach((file, i) => {
    fs.rename(srcFolder + file, outFolder + i + prefix + ".jpg", err => {
      if (err) throw err;
      console.log("rename completed!");
    });
  });
});



Таким образом, мы создали простой скрипт, который позволяет переименовывать (задавать имена) файлам и перемещать их в нужную директорию. Это может не только помочь вам в изучении Node.js, но и значительно сэкономить время.

Этот скрипт можно дорабатывать бесконечно. Можно сделать очень много различных манипуляций. Есть предложения? Пишите в комментариях!

Удачного кодирования - Happy coding и до скорых встреч.

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

Посмотреть код на gitHub abc-rename-files-with-node commit - "rename files with Node.js"



UPDATE: По многочисленным просьбам публикую приятные дополнения, которые позволят:
  1. Легко и быстро запускать скрипт из любой директории.
  2. Сохранять исходное расширение файла.
1. Для этого нам нужно воспользоваться встроенным модулем path. Первое, что нам нужно сделать, это импортировать его в наш скрипт:

var path = require("path");

После этого, мы можем автоматически получать путь к директории, в которой расположен наш скрипт, методом __dirname()

Предположим, что файлы, которые мы будем изменять, лежат в некоей общей для них директории (например - Common как на рис. ниже) и в папке с именем srcImage . В этой же директории мы создадим папку для измененных файлов - outImage

Файловая структура выглядит вот так:



Теперь мы можем легко прописать путь в папку исходных и измененных файлов:

const srcFolder = path.resolve(__dirname, "srcImage") + "/";
const outFolder = path.resolve(__dirname, "outImage") + "/";

Этот скрипт можно легко запустить, если в проводнике виндовс, выбрать нужную папку (на схеме - Common Folder), нажать правую кнопку мыши и , если у вас установлен Bash (а он идет вместе с Node.js), выбрать - Git Bash Here. Таким образом, вы откроете терминал сразу в нужной папке.

Если у вас не получилось, то перейдите в нужную директорию командой

cd folder_name


Теперь, для запуска скрипта нужно набрать:

node rename


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

let extension = path.extname(file);

Теперь, нам остается заменить, внутри функции fs.rename добавляемое окончание (расширение) файла - ".jpg", на extension

fs.rename(srcFolder + file, outFolder + i + prefix + extension, err => {
      if (err) throw err;
      console.log("rename completed!");
    });


Код из файла rename.js полностью:

const fs = require("fs");
var path = require("path");

const srcFolder = path.resolve(__dirname, "srcImage") + "/";
const outFolder = path.resolve(__dirname, "outImage") + "/";

var d = new Date();
var curr_date = d.getDate();
var curr_month = d.getMonth() + 1;
var curr_year = d.getFullYear();

var data_f = curr_date + "-" + curr_month + "-" + curr_year;
var myPrefix = "-t-t-t-";
var prefix = myPrefix + data_f;

fs.readdir(srcFolder, (err, files) => {
  files.forEach((file, i) => {
    let extension = path.extname(file);
    fs.rename(srcFolder + file, outFolder + i + prefix + extension, err => {
      if (err) throw err;
      console.log(`rename - ${file} completed!`);
    });
  });
});



Теперь, если нам нужно поменять название всех файлов в некоторой папке, то мы копируем этот файл и вставляем его на одну директорию выше тех папок - srcImage (исходные изображения) outImage (пустая, вновь созданная, куда будут помещены переименованные файлы).



Открываем rename.js в редакторе и меняем srcImage и outImage на названия ваших папок. Можно это делать и в одной папке, без создания дополнительной outImage, для готовых файлов. В этом случае у вас будут совпадать названия, которые вы вставите на место указанных мной srcImage и outImage.

Префикс, вы можете установить по своему усмотрению и вкусу. Я поставил произвольный - -t-t-t- .

Для примера я поместил в папку srcImage тестовые файлы с разными расширениями:



Теперь, открываю gitBash, как я описывал выше, в CommonFolder и запускаю скрипт:

node rename




В терминале, я вижу перечисленные в порядке процесса переименования файлы ( старые их названия).

Идем в папку переименованных файлов и видим:



Переименование файлов прошло успешно!

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



Посмотреть код на gitHub abc-rename-files-with-node commit - "renaming files using path and saving extension"

                                                                                                                                                             

Телеграм канал - Full Stack JavaScript Developer
Помочь проекту (любая валюта). DONATE


Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook.Пишите мне - kolesnikovy70 почта gmail.com