Translate

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

четверг, 10 мая 2018 г.

Интервью JavaScript: Что такое Promise?

«Мастер интервью с JavaScript» представляет собой серию сообщений, предназначенных для подготовки кандидатов на общие вопросы, с которыми они могут столкнуться при подаче заявки на позицию JavaScript на среднем и старшем уровнях (a mid to senior-level JavaScript position). Это вопросы, которые я часто использую в реальных интервью.




Что такое Promise?

Обещание (Promise)- это объект, который может произвести одно значение в будущем: либо разрешенное значение, либо причина, по которой он не разрешен (например, произошла сетевая ошибка).

Обещание может быть в одном из трех возможных состояний: выполнено- fulfilled, отклонено - rejected или ожидается- pending. Пользователи Promise могут присоединять обратные вызовы для обработки выполненного значения или причины отклонения.

Обещания нетерпеливы, а это означает, что обещание начнет выполнять любую задачу, которую вы даете ему, как только вызывается конструктор обещаний. Если вам нужно лениться, проверьте observables или tasks.

Неполная история Promise - обещаний

Раннее, реализации обещаний и фьючерсов (аналогичная / смежная идея) начали появляться в таких языках, как MultiLisp и Concurrent Prolog еще в 1980-х годах. Использование слова Promise - «обещание» было придумано Барбарой Лисковой и Любой Шририа в 1988 году.

В первый раз, когда я услышал о обещаниях в JavaScript, Node был совершенно новым, и сообщество обсуждало лучший способ обработки асинхронного поведения. Сообщество какое-то время экспериментировало с обещаниями, но в конечном итоге решилось на Node-standard error-first callbacks (стандарт Ноды с ошибкой первого обратного вызова).

Примерно в то же время Dojo добавили обещания через Deferred API. Растущий интерес и активность в конечном итоге привели к недавно сформированной спецификации Promises / A, призванной сделать различные обещания более интероперабельными.

Асинхронное поведение jQuery было реорганизовано вокруг обещаний (Promise). Поддержка обещаний (Promise) jQuery имела большое сходство с Dojo's Deferred, и она быстро стала наиболее часто используемой реализацией (Promise) обещаний в JavaScript из-за огромной популярности jQuery - на то время. Однако, там не было поддержки двухканального (выполненное / отклоненное) поведения цепочки и управления исключениями, на которое люди рассчитывали при создании инструментов поверх обещаний (Promise).

Несмотря на эти недостатки, jQuery официально сделал JavaScript обещания (Promise) мейнстримом, и лучше автономные библиотеки обещаний, таких как Q, When, и Bluebird стали очень популярными. Несовместимость реализации jQuery привела к некоторым важным разъяснениям в спецификации обещаний, которая была переписана и переименована как спецификация Promises / A +.

ES6 принесла Promise / A + совместимый глобальный Promise, и некоторые очень важные API были построены поверх новой стандартной поддержки Promise: особенно спецификация WHATWG Fetch (ссылка заблокирована в России-> use VPN - пр. переводчика) и стандарт Async Functions (проект на 3 стадии на момент написания этой статьи).

Promises - обещаний, описанные здесь, это промисы которые совместимы с спецификациями Promises / A +, с акцентом на стандартную реализацию Promise ECMAScript.

Как работают promis?

Обещание (promis)- это объект, который можно синхронно возвращать из асинхронной функции. Он будет в одном из трех возможных состояний:

  1. Fulfilled(выполнено): onFulfilled() будет вызвано (например: reject() был вызван)
  2. Rejected (отклонено): onRejected() будет вызвано (например: reject() был вызван)
  3. Pending (ожидает): еще не выполнено или отклонено.


Обещание (promis) разрешается - settled, если оно не ожидается (оно было разрешено или отклонено - resolved or rejected). Иногда люди используют resolved и settled как то же самое: not pending..

После settled обещание не может быть resettled. Вызов resolve () или reject () снова не будет иметь эффекта. Важнейшей особенностью является неизменность обещанного обещания (promis).

Собственные обещания JavaScript не раскрывают состояния обещаний. Вместо этого вы должны рассматривать обещание как черный ящик. Только функция, ответственная за создание обещания, будет обладать знанием статуса обещания (promise status) или доступа к разрешению или отказу (resolve or reject).

Вот функция, которая возвращает обещание, которое будет разрешено после заданной задержки:

const wait = time => new Promise((resolve) => setTimeout(resolve, time));

wait(3000).then(() => console.log('Hello!')); // 'Hello!'


Пример кода на CodePen

Наш вызов wait (3000) будет ждать 3000 мс (3 секунды), а затем выведет в консоль «Hello!». Все спецификации, совместимые с обещаниями, определяют метод .then (), который вы используете для передачи обработчиков, которые могут принимать разрешенные или отклоненные значения.

Конструктор обещаний ES6 выполняет функцию. Эта функция принимает два параметра: resolve () и reject (). В приведенном выше примере мы используем только метод resolve (), поэтому я оставил reject () в списке параметров. Затем мы вызываем setTimeout () для создания задержки и вызываем resolve (), когда время ожидания закончено.

Вы можете опционально resolve () или reject () со значениями, которые будут переданы на функции обратного вызова, связанные с .then ().

Когда я отклоняю reject () со значением, я всегда передаю объект Error. Обычно я хочу два возможных состояния разрешения: нормальный счастливый путь или исключение - все, что останавливает нормальный - удачный путь. Передача объекта Error делает это явным.

Важные правила обещания (promise)

Стандарт для обещаний был определен сообществом Promises / A + Существует множество реализаций, которые соответствуют стандарту, включая общие требования стандарта ECMAScript для JavaScript.

Обещания следующей спецификации должны соответствовать определенному набору правил:
  1. Обещание или «thenable» - это объект, который поставляет стандартный метод .then ().
  2. Ожидающее обещание (pending promise) может перейти в отработанное (fulfilled) или отвергнутое (rejected) состояние.
  3. уже установленное состояние fulfilled - исполненное или rejected - отвергнутое. не должно и не может меняться. переходить в другие состояния.
  4. Однажды установленное состоянеи должно иметь значение ( оно может быть и undefined). Это значение не должно меняться.
Изменение в этом контексте относится к сравнению идентичности (===). Объект может использоваться как выполненное значение, а свойства объекта могут мутировать.

Каждое обещание должно предоставить метод .then () со следующей подписью:

promise.then(
  onFulfilled?: Function,
  onRejected?: Function
) => Promise



Метод .then () должен соответствовать следующим правилам:
  1. И onFulfilled (), и onRejected () являются необязательными.
  2. Если предоставленные аргументы не являются функциями, они должны быть проигнорированы.
  3. onFulfilled () будет вызван после того, как обещание будет исполнено, причем значение обещания станет первым аргументом.
  4. onRejected () будет вызываться после того, как обещание будет отклонено, и причина отказа в качестве первого аргумента. Причиной может быть любое допустимое значение JavaScript, но поскольку отклонения по существу являются синонимом исключений, я рекомендую использовать объекты Error.
  5. Ни onFulfilled (), ни onRejected () не могут быть вызваны более одного раза.
  6. .then () можно вызвать много раз по тому же обещанию. Другими словами, обещание может быть использовано для агрегирования обратных вы
  7. .then () должен вернуть новое обещание, promise2.
  8. Если onFulfilled () или onRejected () возвращают значение x, а x является обещанием, promise2 будет блокироваться (предполагать то же состояние и значение, что и x). В противном случае promise2 будет выполнено со значением x.
  9. Если либо onFulfilled, либо onRejected выбрасывает исключение e, promise2 должен быть rejected (отклонен) вместе с e в качестве причины.
  10. Если onFulfilled не является функцией и promise1 выполняется, promise2 должно выполняться с тем же значением, что и promise1.
  11. Если onRejected не является функцией и promise1 отвергается- rejected, promise2 должен быть отклонен по той же причине, что и promise1.


Цепочка обещаний

Именно потому, что .then () всегда возвращает новое обещание, можно связать обещания с точным контролем над тем, как и где обрабатываются ошибки. Обещания позволяют вам имитировать поведение обычного / синхронного кода try / catch.

Подобно синхронному коду, цепочка приведет к последовательности, которая выполняется в последовательном порядке. Другими словами, вы можете сделать:

fetch(url)
  .then(process)
  .then(save)
  .catch(handleErrors)
;



Предполагая, что каждая из функций, fetch (), process () и save () возвращают обещания, process () будет ждать завершения функции fetch () перед запуском, а save () будет ждать завершения process () перед запуском. handleErrors () будет работать только в том случае, если любое из предыдущих обещаний отклоняется.

Вот пример сложной цепочки обещаний с множественными отказами:

const wait = time => new Promise(
  res => setTimeout(() => res(), time)
);

wait(200)
  // onFulfilled() can return a new promise, `x`
  .then(() => new Promise(res => res('foo')))
  // the next promise will assume the state of `x`
  .then(a => a)
  // Above we returned the unwrapped value of `x`
  // so `.then()` above returns a fulfilled promise
  // with that value:
  .then(b => console.log(b)) // 'foo'
  // Note that `null` is a valid promise value:
  .then(() => null)
  .then(c => console.log(c)) // null
  // The following error is not reported yet:
  .then(() => {throw new Error('foo');})
  // Instead, the returned promise is rejected
  // with the error as the reason:
  .then(
    // Nothing is logged here due to the error above:
    d => console.log(`d: ${ d }`),
    // Now we handle the error (rejection reason)
    e => console.log(e)) // [Error: foo]
  // With the previous exception handled, we can continue:
  .then(f => console.log(`f: ${ f }`)) // f: undefined
  // The following doesn't log. e was already handled,
  // so this handler doesn't get called:
  .catch(e => console.log(e))
  .then(() => { throw new Error('bar'); })
  // When a promise is rejected, success handlers get skipped.
  // Nothing logs here because of the 'bar' exception:
  .then(g => console.log(`g: ${ g }`))
  .catch(h => console.log(h)) // [Error: bar]
;


Посмотреть на Codepen

Обработка ошибок

Обратите внимание, что обещания имеют как успешное завершение, так и обработчик ошибок, и очень часто можно увидеть код, который делает это:

save().then(
  handleSuccess,
  handleError
);



Но что произойдет, если handleSuccess () выдает ошибку? Обещание, возвращенное из .then (), будет отклонено, но нет ничего, чтобы поймать отказ - это означает, что ошибка в вашем приложении проглатывается. К сожалению!

По этой причине некоторые люди считают, что приведенный выше код является анти-шаблоном, и вместо этого рекомендуют следующее:


save()
  .then(handleSuccess)
  .catch(handleError)
;



Разница тонкая, но важная. В первом примере ошибка, возникающая в операции save (), будет обнаружена, но ошибка, возникающая в функции handleSuccess (), будет проглатываться.


Без .catch () ошибка в обработчике успеха не реализована.
Во втором примере .catch () будет обрабатывать отклонения от save () или handleSuccess ().


С .catch () обрабатываются оба источника ошибок. (источник диаграммы)

Конечно, ошибка save () может быть сетевой ошибкой, тогда как ошибка handleSuccess () может быть вызвана тем, что разработчик забыл обработать определенный код состояния. Что делать, если вы хотите обращаться с ними по-другому? Вы можете выбрать для них обоих:

save()
  .then(
    handleSuccess,
    handleNetworkError
  )
  .catch(handleProgrammerError)
;



Независимо от того, что вы предпочитаете, я рекомендую прекратить все цепочки обещаний с помощью .catch (). Это стоит повторить:
I recommend ending all promise chains with a .catch().



Как отменить обещание?

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

Вот некоторые распространенные ошибки, которые люди совершают, когда откатываются от обещания:

Добавление .cancel () к обещанию

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

Забыли почистить.

367/5000 Некоторые умные люди поняли, что есть способ использовать Promise.race () как механизм отмены. Проблема заключается в том, что контроль отмены берется из функции, которая создает обещание, которое является единственным местом, где вы можете проводить правильные действия по очистке, такие как очистка тайм-аутов или освобождение памяти путем очистки ссылок на данные и т. д.

забыли обработать reject отклоненного обещания

Знаете ли вы, что Chrome бросает предупреждающие сообщения по всей консоли, когда вы забываете обработать отказ от обещаний? К сожалению!

Слишком сложно

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

Вы хотите переключиться в зависимости от того, есть ли исключение или отмена? Да, конечно. Это работа обещания? По-моему, нет, это не так.

Переосмысление отмены обещаний

Как правило, я передаю всю информацию, которую обещание необходимо определить, как разрешить / отклонить / отменить на время создания обещания. Таким образом, нет необходимости в методе .cancel () по обещанию. Возможно, вам будет интересно узнать, как вы могли бы узнать, собираетесь ли вы отменить время обещания.

«Если я еще не знаю, отменить или нет, как я узнаю, что передать, когда я создам обещание?»


Если бы существовал какой-то объект, который мог бы выдерживать потенциальную ценность в будущем ... о, подождите.

Значение, которое мы передаем, чтобы представлять, отменить или нет, может быть обещанием. Вот как это может выглядеть:


const wait = (
  time,
  cancel = Promise.reject()
) => new Promise((resolve, reject) => {
  const timer = setTimeout(resolve, time);
  const noop = () => {};

  cancel.then(() => {
    clearTimeout(timer);
    reject(new Error('Cancelled'));
  }, noop);
});

const shouldCancel = Promise.resolve(); // Yes, cancel
// const shouldCancel = Promise.reject(); // No cancel

wait(2000, shouldCancel).then(
  () => console.log('Hello!'),
  (e) => console.log(e) // [Error: Cancelled]
); 


Посмотреть на CodePen

Мы используем назначение параметров по умолчанию, чтобы сказать, что он не отменяет по умолчанию. Это делает параметр отмены cancel удобным дополнением. Затем мы устанавливаем таймаут, как и раньше, но на этот раз мы фиксируем идентификатор тайм-аута, чтобы мы могли его очистить позже.

Мы используем метод cancel.then () для обработки отмены и очистки ресурсов. Это будет выполняться только в том случае, если обещание будет отменено, прежде чем у него будет возможность его решить. Если вы отмените слишком поздно, вы упустили свой шанс. Этот поезд покинул станцию.

Примечание. Возможно, вам интересно, для чего предназначена функция noop (). Слово noop означает no-op, что означает функцию, которая ничего не делает. Без него V8 будет вызывать предупреждения: UnhandledPromiseRejectionWarning: Отказ от необработанного обещания. Это хорошая идея, чтобы всегда обрабатывать отклонения обещаний, даже если ваш обработчик является noop ().


Абстрагированное Отклонение обещаний

Это нормально для таймера wait (), но мы можем абстрагировать эту идею дальше, чтобы инкапсулировать все, что вам нужно запомнить:
  1. Отклонить обещание отмены по умолчанию - мы не хотим отменять или бросать ошибки, если не будет отменено обещание отмены.
  2. Не забудьте выполнить очистку, когда вы отклоняете для отмены.
  3. Помните, что очистка onCancel сама может выдать ошибку, и эта ошибка также потребует обработки. (Обратите внимание, что обработка ошибок в примере ожидания отсутствует - легко забыть!)


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


speculation(fn: SpecFunction, shouldCancel: Promise) => Promise



Функция SpecFunction аналогична функции, которую вы передали бы в конструктор Promise, за одним исключением: для него используется обработчик onCancel ():


SpecFunction(resolve: Function, reject: Function, onCancel: Function) => Void






// HOF Wraps the native Promise API
// to add take a shouldCancel promise and add
// an onCancel() callback.
const speculation = (
  fn,
  cancel = Promise.reject() // Don't cancel by default
) => new Promise((resolve, reject) => {
  const noop = () => {};

  const onCancel = (
    handleCancel
  ) => cancel.then(
      handleCancel,
      // Ignore expected cancel rejections:
      noop
    )
    // handle onCancel errors
    .catch(e => reject(e))
  ;

  fn(resolve, reject, onCancel);
});


GitHub

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

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

Давайте используем улучшенную абстракцию библиотеки для перезаписи утилиты waitable () для отмены. Сначала установите спекуляцию:


   npm install --save speculation



Теперь вы можете импортировать и использовать это:


import speculation from 'speculation';

const wait = (
  time,
  cancel = Promise.reject() // By default, don't cancel
) => speculation((resolve, reject, onCancel) => {
  const timer = setTimeout(resolve, time);

  // Use onCancel to clean up any lingering resources
  // and then call reject(). You can pass a custom reason.
  onCancel(() => {
    clearTimeout(timer);
    reject(new Error('Cancelled'));
  });
}, cancel); // remember to pass in cancel!

wait(200, wait(500)).then(
  () => console.log('Hello!'),
  (e) => console.log(e)
); // 'Hello!'

wait(200, wait(50)).then(
  () => console.log('Hello!'),
  (e) => console.log(e)
); // [Error: Cancelled]


GitHub wait-speculation.js

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

Дополнительные возможности Native JS Promise

У родного объекта Promise есть некоторые дополнительные вещи, которые могут вас заинтересовать:
  • Promise.reject() - возвращает отклоненное обещание.
  • Promise.resolve() - возвращает разрешенное обещание.
  • Promise.race() - берет массив (или любой итерабельный) и возвращает обещание, которое разрешает со значением первого разрешенного обещания в итерируемом, или отклоняет по причине первого обещания, которое отвергается.
  • Promise.all() - берет массив (или любой итерабельный) и возвращает обещание, которое разрешает, когда все обещания в итерируемом аргументе разрешаются, или отклоняется по причине первого обещанного обещания, которое отклоняет.


Заключение

Обещания стали неотъемлемой частью нескольких идиом в JavaScript, включая стандарт WHATWG Fetch, используемый для большинства современных запросов ajax, и стандарт Async Functions, используемый для создания синхронного асинхронного кода.

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

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

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

Исследуйте серию



Барбара Лисков; Люба Шрира (1988). «Обещания: лингвистическая поддержка эффективных асинхронных вызовов процедур в распределенных системах». Материалы конференции SIGPLAN '88 по программированию и внедрению языка программирования; Атланта, Джорджия, США, стр. 260-267. ISBN 0-89791-269-1, опубликованный ACM. Также опубликовано в ACM SIGPLAN Notices, том 23, выпуск 7, июль 1988 г.







Автор: Eric Elliott .
Перевод: Kolesnikov Yaroslav



                                                                                                                                                             

среда, 9 мая 2018 г.

Конспект по Bash.

Если вы работаете в ИТ, то как никто знаете о цене времени. Оптимизация рабочего процесса - один из важнейших аспектов работы в ИТ.
Так или иначе, наша работа (будь то верстка сайта, написание модулей, или тестирования приложений) требует повторения одних и тех же действий: быстрые скриншоты с загрузкой на сервер, обработка выделенного текста, конвертация файлов, парсинг данных и многое другое. Чтобы не делать лишних действий, а сконцентрироваться на идее и самой сути ее реализации, еще в 1978 году Стивен Борн разработал командную оболочку [sh] [wiki-sh], которая впоследствии, в 1987 году была усовершенствована Брайаном Фоксом и переросла в то, что мы знаем сегодня как [bash] [wiki-bash] (Bourne again shell).



Вполне логично, что появляется вопрос: "Для чего мне нужно что-то, что написали почти полвека назад?" Так вот ответ на него прост: это "что-то" до сих пор является самым мощным инструментом автоматизации и, де-факто, стандартом для написания простых, но эффективных сценариев на всех unix-based системах. Именно поэтому знать общий синтаксис bash и уметь писать на нем - критический скилл для разработчика.

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

Оболочки и вызов сценариев

Пользовательская оболочка bash может работать в двух режимах - интерактивном и, соответственно, неинтерактивном. Открыть оболочку в Ubuntu можно комбинацией клавиш Ctrl + Alt + F1, привычный графический интерфейс исчезнет, а перед вами откроется один из семи виртуальных терминалов, доступных в дистрибутиве Ubuntu. Если оболочка выдает приглашение (что-то вроде того, которое можно увидеть ниже), то вы работаете в интерактивном режиме:


    user@host:~$



Здесь можно вводить самые разнообразные unix-команды (как то: ls, grep, cd, mkdir, rm) и видеть результат их выполнения. Интерактивной эта оболочка называется потому, что она взаимодействует с пользователем направления. Окружение рабочего стола (графический интерфейс), в семействе систем Debian (к которым относится и Ubuntu), принято размещать в седьмом виртуальном терминале, для того чтобы вернуться к привычному окружение рабочего стола наберите комбинацию Ctrl + Alt + F7. Конечно работать в виртуальных терминалах не слишком удобно, особенно, если нужно редактировать документ и одновременно выполнять какие-либо команды, поэтому в дальнейшем мы будем пользоваться встроенным в графический интерфейс эмулятором виртуального терминала, встроенным в Ubuntu. Открыть его можно комбинацией клавиш Ctrl + Alt + T, или Unity Dash, найдя его в списке программ.

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


    sh скрипт
    bash скрипт



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


    chmod +x скрипт



Кроме этого, в первой строке скрипта необходимо указать которая оболочка должна выполнять этот сценарий. Это можно сделать, разместив в начале соответствующее указание #! / Bin / sh (для оболочки sh) или #! / Bin / bash (соответственно для bash). После этого файл можно будет вызвать на выполнение обратившись к нему в терминале:


    ./скрипт



Комментарии

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


    #!/bin/bash
    # Сценарий, выведет имя пользователя
    whoami



Переменные

Оболочка позволяет создавать и удалять переменные, а также выполнять над ними операции. Переменные в bash могут находиться в 3-х областях видимости:

Локальные переменные - это обычные переменные в внутри одного сценария. Они не доступны другим программам и сценариям, которые запускаются с этой оболочки. Объявляются переменные с помощью символа = (обратите внимание на то, что перед и после = нет пробелов), а с их значением обращаются с помощью символа $:


    name="Петро Петрович"
    echo $name    # вывод значения
    unset name    # удаление переменной



Также можно сказать локальную переменную внутри функции и которая будет доступна только в теле этой функции:


    localлокальная_переменная=значение



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


    exportглобальная_переменная=значение



В bash есть много переменных окружения, которые достаточно часто встречаются в сценариях, например:
  • > HOME - путь к домашнему каталогу пользователя;
  • > PATH - список каталогов, в которых оболочка ищет исполняемые файлы;
  • > PWD - путь к рабочему каталогу;
  • > RANDOM - формирует целое случайное число;
  • > HOSTNAME - имя компьютера, на котором выполняется оболочка;
  • >


Переменные оболочки - это переменные, которые устанавливаются оболочкой и необходимые ей для корректной работы. Эти переменные имеют имена порядкового номера ($ 1, $ 2, $ 3, ...) и содержат аргументы, которые передавались сценария при запуске, как:


    ./some_script.sh VAL1 VAL2  # внутри сценария $1='VAL1', $2='VAL2' 



Переменным можно присваивать значения по умолчанию следующим образом:


    : ${VAR:='значення за замовчуванням'} # Если переменная VAR пуста, присвоить ей "значение по умолчанию"



Массивы и списки

В bash также есть возможность работать с массивами. При работе с массивами часто пользуются переменной окружения IFS - разделителя полей для входных строк (IFS - Input Field Separator). По умолчанию IFS равный Пробельные символа, но может быть изменен для разбиения строки на элементы массива, например, запятыми. Обратите внимание, что для формирования переменных оболочки, которые доступны через $ 1, $ 2 и т.д., используется именно переменная IFS, то есть введен после имени скрипта строку аргументов, будет разделен именно с первым символом, который хранится в этой переменной.

Объявить массив можно следующим образом:


    files[0]=Яблоко
    files[1]=Груша
    echo ${files[*]}    # напечатает элементы массива без учета IFS
    echo ${files[@]}    # напечатает элементы массива с IFS в качестве разделителя.



Доступ к элементу массива можно с помощью срезов: $ {arr: 0: 1}. Удалить первый элемент массива можно с помощью сдвига: shift arr. Добавить в элементы в массив: arr = ("$ {arr [@]}" "Item 1" "Item 2"). Проверить вхождения элемента в массив реализуется с помощью несколько более сложной конструкции:


    if [[ ${arr[(r)some]} == some ]]; then
         # команды, если элемент входит
    else
         # команды, если не входит
    fi



В этом примере arr - некоторый массив, а some - это элемент, который мы проверяем на вхождение.

Подстановки результатов операций.

Присвоить переменной результат работы команды или арифметических операций можно с помощью апострофов, или конструкции $ (выражение):


    now=`data +%T`
    # або
    now=$(data +%T)

    echo now # 19:08:26



Арифметические операции необходимо накладывать в двойные скобки:

   
    foo=$(( ((10 + 5*3) – 7) / 2 ))
    echo $foo    #> 9



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


    echo beg{i,a,u}n #> begin began begun



Стоит вспомнить и о строгости кавычек в bash: одинарные кавычки - строгие, двойные - нестрогие. Это означает, что при подстановке переменных в строку с двойными кавычками, интерпретатор подставит соответствующее значение переменной. Одинарные кавычки выведут строку так, как вы его написали. пример:


    echo "Домашняя директория: $HOME"  #> Домашняя директория: /home/user
    echo 'Домашняя директория: $HOME'  #> Домашняя директория: $HOME



Потоки.

Файл с которого происходит чтение, называют стандартным потоком ввода, а в какой происходит запись, соответственно - стандартным потоком вывода. В bash есть три стандартных потока:

 
    0  stdin   ввод         
    1  stdout  выводд        
    2  stderr  поток ошибок



Для перенаправления потоков используют основные операторы:
  • > - перенаправления потока вывода в файл (файл будет создан, или перезаписан)
  • >> - дописать поток вывода в конец файла;
  • < - перенаправляет данные из файла в поток ввода;
  • <<< - чтение данных из строки, вместо всего содержимого файла (работает для bash 3+)
  • 2> - перенаправляет поток ошибок в файл (файл будет создан, или перезаписан)
  • 2>> - дописать ошибки в конец файла; тадада


Kаналы

Стандартные потоки можно перенаправить не только в файлы, но и на вход других сценариям. Соединение потока вывода одной программы с потоком ввода другой называют каналом или пайпом (pipe). Ниже приведен простой конвейер из трех команд: команда1 перенаправляет свой вывод на вход команды2, которая, в свою очередь, перенаправляет собственный вывод на вход команды3:


  cmd1 | cmd2 | cmd3



Kонвейеры

Конвейеры - это команды, которые соединены операторами ; , && , || для выполнения в определенной последовательности. Операторы организации конвейеров работают следующим образом:
  • > команда1; команда2 - команда2 исполнится после команды1 независимо от результата ее работы команды1;
  • > команда1 && команда2 - команда2 выполнятся только после успешного выполнения команды1 (т.е. с кодом завершения 0);
  • > команда1 || команда2 - команда2 исполнится только после неудачного выполнения команды1 (то есть код завершения команды1 будет отличным от 0)


Условные операторы

В скриптовом языке bash поддерживаются два оператора ветвления: if и case. Оператор if, как и в других языках, выполняет определенный блок указаний, в зависимости от условия. Условие окутывают в двойные квадратные скобки [[...]], которые bash рассматривает как один элемент с кодом выхода. Внутри блока операторов накрытого в [[ ]] разрешается использовать операторы && и ||. примеры:


   # однострочная запись
   if [ ... ]; then echo "true"; else echo "false"; fi;

   ## вложенные условия
   if [ ... ] && [ ... ]; then
        ...
   elif [[ ... && ... ]]; then
        ...
   else
        ...
   fi;



Обратите внимание, что [, условие и] обязательно должны быть разделены пробелами, иначе оболочка воспримет в качестве команды [условие.

В ниже приведена таблица с возможными условиями сравнения:


  # Работа с файлами
  -e    Проверить существует ли файл или директория (-f, -d)
  -f    Файл существует (!-f - не существует)
  -d    Каталог существует (!-f - не существует)
  -s    Файл существует и он не пустой
  -r    Файл существует и доступен для чтения
  -w    ... для записи
  -x    ... для выполнения
  -h    Есть c символической ссылкой

  # Работа со строками
  -z    Пустая строка
  -n    Не пустая строка
  ==    Ровно
  !=    Не ровно

  # Операции с числами
  -eq   Ровно
  -ne   Не ровно
  -lt   Менше
  -le   Менше или ровно
  -gt   Больше
  -ge   Больше или ровно


все основные команды можно посмотреть здесь - Основные команды Bash

примеры:


    if [ `uname` == "Adam"]; then
    echo "Не їж яблуко!"
elif [ `uname` == "Eva"] then
    echo "Не бери яблуко!"
else
    echo "Яблука зараз дуже дорогі!"
fi;



Если необходимо сделать выбор из нескольких альтернатив, пригодится оператор case. Принцип его работы легче понять на примере:


 case "$extension" in
    (jpg|jpeg)
        echo "Це зображення у форматі jpeg."
    ;;
    png)
        echo "Це зображення у форматі png"
    ;;
    gif)
         echo "А це гіфочка))"
    *)
        echo "Оу! Це взагалі не зображення!"
    ;;
 esac


В примере оператор проверяет значение переменной $ extension на совпадение с одним из шаблонов и в случае совпадения выполнит соответствующий блок кода. В случае, если не будет найдено совпадений, выполнятся указания, соответствуют шаблону * .

Циклы

Язык оболочки дает пользователю возможность организовывать циклическое выполнение инструкций при помощи циклов:
  1. > while
  2. > for
  3. > select
Оператор while описывается следующим образом:


    while условие do
         тeло
    done



Интерпретатор в первую очередь выполняет команды, описанные в условии. Если результат выполнения нулевой, то выполняется тело, а после ее выполнения, переход к следующей итерации, в противном случае происходит выход из цикла. В условии может быть любая допустимая команда. пример:


   #!/bin/sh
   # Квадраты чисел от 1 до 10
   x=0
   while [ $x –lt 10 ] do 
   #значение переменной x меньше 10?
       echo $(($x*$x))
       x=`expr $x + 1` # увеличиваем х на 1
   done



Цикл for выполняет тело для каждого элемента из списка. Синтаксис цикла for таков:


   for имя in елемент1 елемент2 ... елементN do
        тeло
   done



В качестве элементов обычно используют различные шаблоны (wildcards). Очень удобно применять for для прохождения по каталогам и выполнения операций над группой файлов. В примере ниже, цикл проходит по всем файлах с расширением * .bash, перемещает их в директорию ~ / scripts и добавляет их права на исполнение.


   #!/bin/sh
   # Перемещение всех скриптов из ~ в директорию ~/scripts
   for FILE in $HOME/*.bash do
        mv $FILE ${HOME}/scripts
        chmod +x ${HOME}/scripts/${FILE}
   done


Цикл select помогает организовать удобное меню выбора и применяется тогда, когда пользователь должен выбрать один элемент из предложенного списка. В общем цикл select имеет такой же синтаксис как и цикл for:


  select ответ in елемент1 елемент2 ... елементN do
       тіло
done



При выполнении этого оператора, все элементы из списка высвечиваются на экране со своими порядковыми номерами в виде списка вариантов ответа, после списка выводится специальное приглашение для ввода. Обычно оно имеет вид # ? . Введенный пользователем номер списка записывается в переменную ответ. Если ответ содержит номер пункта меню, то в переменную заносится значение соответствующего элемента из списка. Если в списке нет введенного пункта, список будет показан снова. После того, как пользователь сделает правильный выбор, выполнятся указания в теле, а цикл перейдет к следующей итерации и все действия повторятся с самого начала - именно поэтому работу цикла select желательно прерывать


   #!/bin/sh

   echo -n "Введите название пакета: " && read PACKAGE
   PS3="Выберите пакетный менеджер : "
   select ITEM in bower, npm, pip do
        case $ITEM in
            bower) bower install $PACKAGE ;;
            npm) npm install $PACKAGE ;;
            pip) pip install $PACKAGE ;;
        esac
        break
   done



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

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

Функции.

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


   имя_функции () {
        команды
   }

   имя_функции    # обращение к функции



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

Функция может принимать аргументы и возвращать после своего выполнения результат - код выхода. Функция направляется в своих аргументов точно так же, как и в локальных переменных, с помощью позиционных переменных - $ 1, $ 2 и тд. Результат работы можно поворачивать с помощью команды return. Например, функция, которая принимает параметр (имя) и заканчивая свою работу с кодом 0:


   #!/bin/sh
   #функция с параметром
   greeting() {
        if [ -n "$1" ]; then
            echo "Привет, $1!"
        else
             echo "Привет, неизвестный!"
        fi
        return 0
   }

   greeting пользователь    #> Привет, пользователь!
   greeting               #> Привет, неизвестный!



Команда return возвращает код завершения 0 - это код успешного завершения сценария. Каждая программа по завершению работы записывает в переменную окружения #? код завершения - число от 0 до 255. С помощью этой переменной можно определять статус выполнения каждой отдельной команды или скрипта. Если программа завершилась ошибкой, кодом завершения будет целое число отличное от нуля. Обратите внимание, что если сценарий завершается командой exit без параметров, кодом завершения сценария будет код завершения последней выполненной команды.

Отладка сценариев.

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


   #!/bin/sh опция



Можно выбирать среди следующих функций:
  1. > -n - читать все команды, но не выполнять их;
  2. > -v - выводить все строки по мере их обработки интерпретатором;
  3. > -x - выводить все команды и их аргументы по мере их выполнения.
Для налаживания сценария частями, нужный фрагмент замечают вызовом команды set с соответствующей опцией из таблицы. Причем, для включения режима отладки, перед опцией указывают символ - для отключения режима отладки используют + .


   set –x # включаем режим  отладки
   ...
   set +x # выключаем режим  отладки



Общая практика налаживания заключается в том, чтобы прежде чем запустить его на выполнение, необходимо проверить его синтаксис с помощью опции -n . Для большей детальности можно комбинировать ключи -nv . После исправления синтаксических ошибок проводится отладка с помощью опции -x .

Послесловие.

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

Если вас заинтересовал скриптинг на Bash, прошу поддержать меня, распространяя статью среди своих друзей.

Рад буду услышать конструктивную критику и замечания в комментариях.






Выражаю благодарность изданию codeguida за любезно предоставленный материал.

Автор: denysdovhan.
Перевод: Kolesnikov Yaroslav.                                                                                                                                                              

React.js (2) Разбиваем на компоненты.

Хранить весь код в одном файле index.js неудобно и поэтому мы разобьем наш файл на компоненты.

Первая часть о том, как развернуть быстро и легко React приложение на локальном сервере находится здесь - React.js Настройка окружения.



Каждый компонент может быть повторно использован и представляет собой некую отдельную, самостоятельную часть (можно представить как строительный блок) кода. Будет правильным поместить их в отдельные файлы. Поэтому в папке src мы создадим для всех компонентов отдельную папку - components. В ней создадим два файла - Article.js и App.js.

В них мы поместим код (функцию) наших компонентов из файла index.js.

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

Для этого мы пропишем строку import React from 'react' в самом начале файлов Article.js и App.js.

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

export default App - для App - компонента.

export default Article - для Article - компонента.

В компонент App нам нужно импортировать код компонента Article, так как он принимает участие в строительстве самого App - компонента. вспоминаем:

function App() {
 return (
    <div>
        <h1>App Name</h1>
        <Article/>
    </div>
  );
}



Именно поэтому мы в фале App.js пишем - import Article from './Article'

После этих изменений стоит запустить сервер (в КС (bash) - npm start. см. Здесь! и убедиться, что все продолжает работать!

На данном этапе наш код компонента Article показывает статические названия, которые мы прописали внутри тегов title, body и т.д. Но нам нужно сделать таким образом, чтобы туда автоматически подставлялись текст, заголовок и прочие необходимые атрибуты статьи.

Для этого мы можем использовать js - переменные ( внутри фигурных скобок - { js-variable } ).

Наши компоненты (App и Article) это обычные функции и им в аргументы мы можем передавать нужные данные. Все данные будут приходить в первом аргументе и его принято называть props.

Коль скоро мы хотим получить в компоненте Article статью, то мы можем создать переменную const {article} = props - используем деструктуризацию объекта и все эти переменные мы сможем использовать внутри JSX.({ article.title }, { article.text } и пр.)

Файл Article.js

import React from 'react'

function Article(props) {
  const {article} = props
  const body = <section>{ article.text }</section> 
 return(
      <div>
        <h2>{ article.title }</h2> 
        { body }
        <h3>
         "creation date : "{ (new Date(article.date)).toDateString()}
        </h3>
      </div>
    );
}

export default Article



Файл App.js

import React from 'react'
import Article from './Article'

import articles from '../fixtures.js'

function App() {
 return (
    <div>
        <h1>App Name</h1>
        <Article article={articles[0]}/>
    </div>
  );
}

export default App



Здесь стоит пояснить, что строкой import articles from '../fixtures.js' мы подключаем файл в котором будут храниться сами статьи.

Для того, чтобы передать наши статьи article={articles[0]}
Файл fixtures.js

export default [
    {
        "id": "56c782f18990ecf954f6e027",
        "date": "2016-06-09T15:03:23.000Z",
        "title": "React Is Awesome!!!",
        "text": "React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes. \n We don't make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code. Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep state out of the DOM.",
        "comments": [
            {
                "id": "qwerqwer",
                "user": "Gilliam Underwood",
                "text": "Velit anim deserunt elit velit est fugiat duis eiusmod eu do incididunt ut tempor voluptate. Officia dolor aliqua id anim mollit pariatur id commodo. Laborum minim non ut aliquip commodo est consectetur. Mollit eu aliqua tempor est nulla ullamco irure. Sit non amet et eiusmod cillum ex cillum anim incididunt ad laboris mollit. Sunt quis incididunt elit ea qui non ullamco aliquip consequat voluptate eiusmod est. Irure laboris amet culpa sit aliquip."
            },
            {
                "id": "lkjhsdlfkg",
                "user": "Dolly Franklin",
                "text": "Aliquip id nostrud adipisicing irure. Labore reprehenderit ea ex officia ullamco incididunt consequat elit amet quis commodo. Fugiat amet veniam cillum ut aliquip velit est esse minim fugiat eiusmod sint. Commodo ea in culpa deserunt."
            },
            {
                "id": "zxcvzcxvzxcv",
                "user": "Brennan Atkins",
                "text": "Nisi sit nisi cillum dolor fugiat sint do nostrud ex cillum cupidatat. Culpa do duis non et excepteur labore dolor culpa qui tempor veniam. Ex labore deserunt qui sit aute ad incididunt do cupidatat eiusmod reprehenderit ad. Qui laborum qui voluptate velit et consectetur ipsum enim dolore minim. Est sint velit tempor reprehenderit. Qui consectetur ad minim consequat."
            },
            {
                "id": "fghjfghjfghj",
                "user": "Jodi Humphrey",
                "text": "Non amet amet ut magna culpa dolore consequat occaecat. Commodo adipisicing laboris voluptate enim mollit mollit anim aliquip deserunt nostrud deserunt cillum est. Ad eu cupidatat dolor nostrud et minim id in dolor occaecat ad magna elit. Laboris elit laboris aliquip Lorem reprehenderit id amet reprehenderit laborum minim incididunt cupidatat eiusmod."
            },
            {
                "id": "ertyoertywte",
                "user": "Joyce Weber",
                "text": "Non qui Lorem qui commodo sint in esse non aliqua pariatur mollit veniam. Elit labore ad nisi anim adipisicing tempor velit commodo adipisicing ipsum ut. Nostrud cillum aliquip adipisicing id do occaecat est eiusmod adipisicing duis. Magna dolore et non nisi in non cillum officia elit non esse proident irure aute. Proident mollit amet enim dolore eiusmod dolor qui. Eiusmod reprehenderit cillum sit deserunt nostrud enim duis excepteur. Excepteur pariatur sunt in ipsum id minim est mollit."
            }
        ]
    },
    {
        "id": "56c782f17b4e0ba78c7ad717",
        "date": "2016-04-09T18:03:23.000Z",
        "title": "Quis occaecat",
        "text": "Quis occaecat duis aliqua reprehenderit excepteur nisi deserunt excepteur elit magna. Magna cillum anim veniam deserunt voluptate occaecat irure fugiat laboris proident. Tempor do magna deserunt cillum laborum cillum ut.\n\nEst sunt cupidatat in deserunt sit aliqua duis. Mollit consequat duis aliquip occaecat pariatur non do eiusmod dolore amet deserunt ullamco. Ea minim tempor exercitation do tempor nostrud dolor minim veniam laboris commodo ex duis. Do nostrud voluptate ullamco consequat anim tempor voluptate incididunt aliqua tempor.\n\nIn irure quis nostrud do. Labore laboris irure culpa reprehenderit pariatur laboris in commodo culpa enim cillum magna. Magna ipsum pariatur sunt in reprehenderit ipsum duis officia voluptate adipisicing ad officia. Duis est sint mollit amet laborum magna non quis nulla ipsum in veniam sit. Amet velit consequat esse esse ea. Ipsum non do ut cillum in adipisicing labore non commodo do laborum sunt.",
        "comments": [
            {
                "id": "qwerqwertyy",
                "user": "Gilliam Underwood",
                "text": "Velit anim deserunt elit velit est fugiat duis eiusmod eu do incididunt ut tempor voluptate. Officia dolor aliqua id anim mollit pariatur id commodo. Laborum minim non ut aliquip commodo est consectetur. Mollit eu aliqua tempor est nulla ullamco irure. Sit non amet et eiusmod cillum ex cillum anim incididunt ad laboris mollit. Sunt quis incididunt elit ea qui non ullamco aliquip consequat voluptate eiusmod est. Irure laboris amet culpa sit aliquip."
            },
            {
                "id": "sdfgsdfghu7u7urtv",
                "user": "Jodi Humphrey",
                "text": "Non amet amet ut magna culpa dolore consequat occaecat. Commodo adipisicing laboris voluptate enim mollit mollit anim aliquip deserunt nostrud deserunt cillum est. Ad eu cupidatat dolor nostrud et minim id in dolor occaecat ad magna elit. Laboris elit laboris aliquip Lorem reprehenderit id amet reprehenderit laborum minim incididunt cupidatat eiusmod."
            }
        ]
    },
    {
        "id": "56c782f1978fdf9a0100df52",
        "date": "2016-06-02T11:03:23.000Z",
        "title": "Hello my new world",
        "text": "Culpa dolor deserunt veniam irure amet officia excepteur labore nisi labore ad labore laborum aute. Ea irure sit exercitation ex. Aliquip dolore duis ullamco labore qui. Et anim irure laborum quis ipsum. Adipisicing culpa est ea velit veniam dolor nisi. Sit cupidatat velit commodo eu.\n\nUt nulla ut irure cillum irure sint sunt cupidatat tempor laboris incididunt elit occaecat fugiat. Reprehenderit enim cupidatat consectetur pariatur ad pariatur consequat veniam do fugiat Lorem laborum do velit. Nulla aute magna magna nisi officia et. Aute adipisicing eu eiusmod tempor exercitation sint non enim laboris dolor adipisicing.\n\nEa do sint pariatur voluptate ad culpa irure. Cillum pariatur deserunt fugiat elit. Exercitation labore amet deserunt magna. Velit veniam aute officia aliqua ipsum veniam pariatur. Aliquip ullamco fugiat officia non sunt ad consequat ipsum est esse commodo reprehenderit. Ad quis consectetur est exercitation fugiat eiusmod. Laborum reprehenderit esse qui irure.",
        "comments": [
            {
                "id": "kjfviudfv089w74",
                "user": "Joyce Weber",
                "text": "Non qui Lorem qui commodo sint in esse non aliqua pariatur mollit veniam. Elit labore ad nisi anim adipisicing tempor velit commodo adipisicing ipsum ut. Nostrud cillum aliquip adipisicing id do occaecat est eiusmod adipisicing duis. Magna dolore et non nisi in non cillum officia elit non esse proident irure aute. Proident mollit amet enim dolore eiusmod dolor qui. Eiusmod reprehenderit cillum sit deserunt nostrud enim duis excepteur. Excepteur pariatur sunt in ipsum id minim est mollit."
            },
            {
                "id": "r23uyrghasdfb7",
                "user": "Joyce Weber",
                "text": "Non qui Lorem qui commodo sint in esse non aliqua pariatur mollit veniam. Elit labore ad nisi anim adipisicing tempor velit commodo adipisicing ipsum ut. Nostrud cillum aliquip adipisicing id do occaecat est eiusmod adipisicing duis. Magna dolore et non nisi in non cillum officia elit non esse proident irure aute. Proident mollit amet enim dolore eiusmod dolor qui. Eiusmod reprehenderit cillum sit deserunt nostrud enim duis excepteur. Excepteur pariatur sunt in ipsum id minim est mollit."
            }
        ]
    },
    {
        "id": "56c782f1e17f4f9311dfaa2c",
        "date": "2016-05-19T23:03:23.000Z",
        "title": "Voluptate est officia",
        "text": "Voluptate est officia pariatur tempor labore consequat consequat consectetur culpa enim. Amet laborum commodo in ullamco magna aliquip. Cupidatat veniam adipisicing labore irure nostrud sunt proident aute in. Sit Lorem consequat cillum enim id excepteur aliqua nostrud sint quis aute est est dolor. Sunt culpa est magna ad qui consequat exercitation. Enim sit ex do cupidatat laborum.\n\nOccaecat do tempor ex in dolor cupidatat do quis laboris anim. Et duis esse pariatur magna ex ipsum ut do ut id cillum. Nostrud fugiat sit minim ea. Nisi nulla sunt et et voluptate. Velit reprehenderit enim nulla mollit dolore excepteur Lorem do Lorem do cillum est qui. Ipsum mollit duis laboris incididunt non sit sunt proident. Aute voluptate id sunt aute proident officia.\n\nEnim ut nulla cillum officia cupidatat eiusmod amet laborum do labore id. Laborum in laboris aliquip anim consectetur magna reprehenderit consequat eiusmod esse Lorem consequat aliqua. Eiusmod voluptate mollit sint consectetur eu deserunt laboris ad et sunt nulla fugiat quis non. Dolor qui do cupidatat proident mollit amet sint pariatur non aliquip enim ex.",
        "comments": [
            {
                "id": "rflsbvyeuwr334rg5",
                "user": "Random Name",
                "text": "Non qui Lorem qui commodo sint in esse non aliqua pariatur mollit veniam. Elit labore ad nisi anim adipisicing tempor velit commodo adipisicing ipsum ut. Nostrud cillum aliquip adipisicing id do occaecat est eiusmod adipisicing duis. Magna dolore et non nisi in non cillum officia elit non esse proident irure aute. Proident mollit amet enim dolore eiusmod dolor qui. Eiusmod reprehenderit cillum sit deserunt nostrud enim duis excepteur. Excepteur pariatur sunt in ipsum id minim est mollit."
            },
            {
                "id": "234faasffasgfq3r3eda",
                "user": "Felix Soyferman",
                "text": "Non qui Lorem qui commodo sint in esse non aliqua pariatur mollit veniam. Elit labore ad nisi anim adipisicing tempor velit commodo adipisicing ipsum ut. Nostrud cillum aliquip adipisicing id do occaecat est eiusmod adipisicing duis. Magna dolore et non nisi in non cillum officia elit non esse proident irure aute. Proident mollit amet enim dolore eiusmod dolor qui. Eiusmod reprehenderit cillum sit deserunt nostrud enim duis excepteur. Excepteur pariatur sunt in ipsum id minim est mollit."
            },
        ]
    },
    {
        "id": "56c782f197fe2bad471b3740",
        "date": "2016-06-04T15:03:23.000Z",
        "title": "Ex sunt sunt aliqua",
        "text": "Ex sunt sunt aliqua reprehenderit aliqua occaecat. Minim anim commodo officia veniam proident aute cillum eu sunt aute nostrud. Laboris fugiat velit ut pariatur occaecat adipisicing pariatur occaecat. Duis sint enim et consectetur quis pariatur laborum excepteur. Ipsum aliquip qui laborum commodo consectetur do velit veniam occaecat. Ad nisi dolor cillum elit magna dolor voluptate ea. Enim in duis ea consequat sunt Lorem aute.\n\nEst elit sunt quis officia reprehenderit do elit commodo eiusmod esse voluptate. Sit ipsum commodo sint voluptate culpa labore elit magna ullamco nostrud. Laboris magna magna anim labore mollit irure voluptate. Aute non magna aliqua aliqua sunt. Velit mollit consectetur aliqua id tempor ut. Tempor cupidatat aliquip excepteur occaecat incididunt nulla Lorem sint.\n\nNon commodo anim deserunt in et aliquip incididunt ut consectetur sunt esse commodo deserunt et. Tempor fugiat laboris cillum laboris labore. Deserunt quis ad do labore amet culpa officia. Esse et officia nostrud tempor occaecat officia anim incididunt amet sunt excepteur Lorem. Aute occaecat magna velit nisi sit anim consequat velit qui pariatur. Esse incididunt id officia aliqua anim ut et.",
        "comments": [
            {
                "id": "23rfasdfasdvg",
                "user": "Hello World",
                "text": "Non qui Lorem qui commodo sint in esse non aliqua pariatur mollit veniam. Elit labore ad nisi anim adipisicing tempor velit commodo adipisicing ipsum ut. Nostrud cillum aliquip adipisicing id do occaecat est eiusmod adipisicing duis. Magna dolore et non nisi in non cillum officia elit non esse proident irure aute. Proident mollit amet enim dolore eiusmod dolor qui. Eiusmod reprehenderit cillum sit deserunt nostrud enim duis excepteur. Excepteur pariatur sunt in ipsum id minim est mollit."
            },
            {
                "id": "fqasfd4r35tga",
                "user": "Sofia Michailenko",
                "text": "Non qui Lorem qui commodo sint in esse non aliqua pariatur mollit veniam. Elit labore ad nisi anim adipisicing tempor velit commodo adipisicing ipsum ut. Nostrud cillum aliquip adipisicing id do occaecat est eiusmod adipisicing duis. Magna dolore et non nisi in non cillum officia elit non esse proident irure aute. Proident mollit amet enim dolore eiusmod dolor qui. Eiusmod reprehenderit cillum sit deserunt nostrud enim duis excepteur. Excepteur pariatur sunt in ipsum id minim est mollit."
            }
        ]
    },
    {
        "id": "56c782f1a2c2c3268ddb3206",
        "date": "2016-06-08T19:03:23.000Z",
        "title": "Commodo laborum sit nostru",
        "text": "Commodo laborum sit nostrud reprehenderit cupidatat officia laboris. Ipsum minim culpa in enim. Voluptate dolor ea irure nisi incididunt enim magna.\n\nCupidatat quis cillum velit culpa tempor esse irure nostrud ea consectetur officia fugiat irure qui. Enim quis officia do in. Velit veniam ipsum consequat aliqua duis voluptate. Minim nisi ex aute ad.\n\nNisi Lorem ex tempor adipisicing labore. Quis occaecat fugiat pariatur labore culpa cillum laboris. Labore occaecat ut laborum sit ex do sit. Deserunt consectetur elit aute laboris est deserunt officia ullamco sit laboris officia aliquip. Aliqua ut sunt nostrud voluptate excepteur quis incididunt Lorem ut.",
        "comments": [
            {
                "id": "23qwfasdf3",
                "user": "Brad McKeon",
                "text": "Non qui Lorem qui commodo sint in esse non aliqua pariatur mollit veniam. Elit labore ad nisi anim adipisicing tempor velit commodo adipisicing ipsum ut. Nostrud cillum aliquip adipisicing id do occaecat est eiusmod adipisicing duis. Magna dolore et non nisi in non cillum officia elit non esse proident irure aute. Proident mollit amet enim dolore eiusmod dolor qui. Eiusmod reprehenderit cillum sit deserunt nostrud enim duis excepteur. Excepteur pariatur sunt in ipsum id minim est mollit."
            },
            {
                "id": "dadsafw4f45w",
                "user": "Dolly Franklin",
                "text": "Aliquip id nostrud adipisicing irure. Labore reprehenderit ea ex officia ullamco incididunt consequat elit amet quis commodo. Fugiat amet veniam cillum ut aliquip velit est esse minim fugiat eiusmod sint. Commodo ea in culpa deserunt."
            },
            {
                "id": "234erasfdastw4a",
                "user": "Brennan Atkins",
                "text": "Nisi sit nisi cillum dolor fugiat sint do nostrud ex cillum cupidatat. Culpa do duis non et excepteur labore dolor culpa qui tempor veniam. Ex labore deserunt qui sit aute ad incididunt do cupidatat eiusmod reprehenderit ad. Qui laborum qui voluptate velit et consectetur ipsum enim dolore minim. Est sint velit tempor reprehenderit. Qui consectetur ad minim consequat."
            }
        ]
    },
    {
        "id": "56c782fghgfc2c3268ddb3206",
        "date": "2016-06-08T19:03:23.000Z",
        "title": "Lorem Ipsum dolor",
        "text": "Commodo laborum sit nostrud reprehenderit cupidatat officia laboris. Ipsum minim culpa in enim. Voluptate dolor ea irure nisi incididunt enim magna.\n\nCupidatat quis cillum velit culpa tempor esse irure nostrud ea consectetur officia fugiat irure qui. Enim quis officia do in. Velit veniam ipsum consequat aliqua duis voluptate. Minim nisi ex aute ad.\n\nNisi Lorem ex tempor adipisicing labore. Quis occaecat fugiat pariatur labore culpa cillum laboris. Labore occaecat ut laborum sit ex do sit. Deserunt consectetur elit aute laboris est deserunt officia ullamco sit laboris officia aliquip. Aliqua ut sunt nostrud voluptate excepteur quis incididunt Lorem ut."
    }

]


Теперь наш сайт будет выглядеть так.



В props мы можем передавать все что угодно. Это объект, который может передавать в компонент данные. Например

<Article article={articles[0] foo="bar"}/> - передаем строку и нам не нужно заворачивать ее в фигурные скобки.

<Article article={articles[0] flag={ true }}/> передали флажок. Можно передать просто flag без значений и он передастся как true Таким образом мы разбили наше приложение на компоненты и связали их между собой. Подключили вывод текста одной статьи. Продолжение знакомства с React.js смотрите в следующей части - React.js (3) Там мы будем добавлять интерактивность нашим компонентам. Поставим кнопку с изменяющимся текстом для открытия\скрытия статьи.
Все статьи по React.js

                                                                                                                                                             

React.js (3) Добавляем интерактивность.



Все статьи по React.js



Добавляем кнопку к нашему приложению. Для этого в файле Articles.js добавили - выделено красным:

import React from 'react'

function Article(props) {
  const {article} = props
  const body = <section>{ article.text }</section> 
 return(
      <div>
        <h2>
          { article.title }
          <button onClick={handleClick}>close</button>
        </h2> 
        { body }
        <h3>
         "creation date : "{ (new Date(article.date)).toDateString()}
        </h3>
      </div>
    );
}
function handleClick() {
  console.log('---', 'clicked')
}

export default Article


Мы добавили кнопку и "проверочную" функция, которая при клике выведет в консоль:



Теперь самое время подумать, как мы будем открывать и закрывать текст статьи этой кнопкой.

В мире реакта мы используем декларативное программирование. То есть мы не описываем что нужно убрать этот текст или напротив - добавить текст в HTML. Мы описываем состояние компонента. И наши объекты могут находиться в различных состояниях. В нашем случае это состояния с открытым и закрытым текстом.

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

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

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

Для этого нам понадобится базовый компонент реакта - изменяем первую строку "импорта":


import React, {Component} from 'react'

class Article extends Component {
  render() {
    Cюда весь код функции Article без объявления
  }
}


Единственное что - наши props. Для них следует добавить - this.props, потому как они уже не будут приходить как аргумент, а будут частью компонента - Component, расширением коего и является наша функция Article

Проверим. Ничего не должно измениться на нашем сайте.

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


import React, {Component} from 'react'

class Article extends Component {
  // constructor(props) {
  //   super(props)

  //   this.state = {
  //     isOpen: true
  //   }
  // }
state = {
  isOpen: true
}

  render() {
      const {article} = this.props
      console.log('---', this.props)
      const body = <section>{ article.text }</section> 
    return(
      <div>
        <h2>
          { article.title }
          <button onClick={handleClick}>close</button>
        </h2> 
        { body }
        <h3>
          "creation date : "{ (new Date(article.date)).toDateString()}
        </h3>
      </div>
    );
  }
}



function handleClick() {
  console.log('---', 'clicked')
}

export default Article

Красным цветом мы описали состояние компонента по старому. А ниже, зеленым, описали то же самое, но новым стилем. Поэтому все что красное - можно смело закомментировать. Это совершенно эквивалентные записи просто короткая запись с экспериментальным синтаксисом.

Теперь, нам нужно использовать это состояние. Мы будем его использовать там, где мы создали переменную body и скажем. что если наше состояние активное (isOpen: true), то мы будем показывать эту секцию, а нет - значит рендерить пустоту.

Наше состояние храниться в this.state. Это специальный атрибут, наподобие this.props. Ниже написанный код можно выразить так: Если наше состояние isOpen (true), то мы показываем секцию, а если нет, то не показываем.


const body = this.state.isOpen && <section>{ article.text }</section> 



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



Стоит изменить значение isOpen: на true и статья будет открыта (показана на экране).

Теперь нам осталось сделать так, чтобы изменять состояние.

для смены состояний есть специальный метод ,code>this.set state. Но для того, чтобы работать с контекстом, нам нужно привязать этот контекст к обработчику. существует множество способов как это сделать.

<button onClick={handleClick.bind(this)}>close</button>


Но так делать не стоит.

Мы можем описать этот метод в конструкторе :


import React, {Component} from 'react'

class Article extends Component {
  constructor(props) {
    super(props)

       this.state = {
      isOpen: true
    }
    this.handleClick = handleClick.bind(this)
  }


  render() {
      const {article} = this.props
      console.log('---', this.props)
      const body = this.state.isOpen && <section>{ article.text }</section> 
    return(
      <div>
        <h2>
          { article.title }
          <button onClick={this.handleClick}>close</button>
        </h2> 
        { body }
        <h3>
          "creation date : "{ (new Date(article.date)).toDateString()}
        </h3>
      </div>
    );
  }
  handleClick = () =>{
    console.log('---', 'clicked')
  }
}

export default Article



Красным цветом - это старый развернутый синтаксис. Его можно смело заменить новым - выделен зеленым цветом. Все красное- из кода можно смело удалить!

Во вновь добавленную функцию (зеленым) мы добавили проверочный вывод в консоль. и this.setState() в которую мы передали объект у которого мы задаем новое состояние isOpen = true или isOpen = false, но мы можем отталкиваться от предыдущего состояния и изменять его - isOpen: !this.state.isOpen

setState() - операция асинхронная, поэтому там у нас будет старое состояние (!this.state.isOpen).

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

Осталось только поменять текст на кнопке -вместо надписи кнопки - "close", мы добавим функцию, которая будет изменять текст в зависимости от состояния:

{this.state.isOpen ? 'close' : 'open'}

Файл Article.js полностью:

import React, {Component} from 'react'

class Article extends Component {
      state = {
        isOpen: true
    }

  render() {
      const {article} = this.props
      const body = this.state.isOpen && <section>{ article.text }</section> 
    return(
      <div>
        <h2>
          { article.title }
          <button onClick={this.handleClick}>
            {this.state.isOpen ? 'close' : 'open'}
          </button>
        </h2> 
        { body }
        <h3>
          "creation date : "{ (new Date(article.date)).toDateString()}
        </h3>
      </div>
    );
  }
  handleClick = () =>{
    console.log('---', 'clicked')
    this.setState({
      isOpen: !this.state.isOpen
    })
  }
}

export default Article



Первая часть React                                                                                                                                                              


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