How to start react app
How to start react app
Создаем приложение React с нуля в 2021 году
Замысел проекта
До этого подобную тему освещал Jedai Saboteur в своей статье Creating a React App… From Scratch (англ.), на которую ввиду ее грамотности даже сделали ссылку в официальной документации React.
Как бы то ни было, но время идет, и я решил создать современное приложение React с нуля в 2021 году. В итоге было решено добавить в цепочку инструментов ряд “важных элементов” и задействовать последние версии основных библиотек. В некотором смысле у меня получилась последняя версия вышеприведенного руководства.
Задача
Тем не менее помимо настройки простого рабочего приложения я также определил пару дополнительных, “важных” по меркам современного стека, требований:
Инструменты
Озадачившись списком необходимых инструментов, я решил обратиться к документации React.
После прочтения раздела Creating Toolchain from Scratch я прикинул следующий список:
Этот краткий отрывок достаточно подробно раскрывает суть необходимых компонентов. В итоге на их роли я выбрал:
Это вполне типичные варианты. Даже если вам не приходилось заниматься самостоятельной настройкой этих инструментов, то вы наверняка с ними либо работали, либо просто о них слышали.
Однако, согласно моим требованиям, все еще недостает одного элемента: библиотеки управления состоянием.
Redux могла стать очевидным выбором, но я предпочел Kea. Дело в том, что разработана Kea на базе Redux, но при этом существенно упрощает управление состоянием.
По правде говоря, здесь я определенно предвзят, так как выбрал Kea больше из-за того, что использую эту библиотеку на работе, а разработал ее мой коллега.
Начало
В src будет храниться весь исходный код проекта, а в public мы разместим статические ресурсы.
Настройка
Наше руководство будет не универсальным, а обучающим, и работа с возникающими сложностями станет его неотъемлемой частью.
В качестве примера я решил взять для этого руководства webpack v5, который вызвал ряд проблем совместимости с конфигурациями, используемыми мной ранее в проектах с webpack v4. Как обычно разобраться с этой проблемой и попутно запастись дополнительными знаниями мне помогла документация, различные статьи и посты на Stack Overflow.
Babel
Для работы Babel требуется еще несколько пакетов, которые устанавливаются так:
babel-core — это компилятор, то есть сам основной компонент.
babel-cli позволит использовать компилятор из командной строки.
Последние три пакета — это “шаблоны” (настройки) Babel для работы с различными сценариями использования. present-env избавляет нас лишних проблем, позволяя писать современный JS-код и обеспечивая его работоспособность на различных клиентах. preset-typescript и preset-react говорят сами за себя: так как используем мы и TypeScript, и React, то нам понадобятся они оба.
TypeScript
В этом проекте мы будем использовать TypeScript, поэтому у него будут свои дополнительные настройки.
Сначала установим пакет typescript :
Забегая чуть вперед, я предлагаю вам также установить следующие пакеты, если вы собираетесь следовать руководству до конца:
В них содержатся объявления типов для модулей, которые мы задействуем в проекте.
Можете смело менять приведенную конфигурацию под свои нужды. Тем не менее важно сохранить эти опции:
Webpack
Для работоспособности этому инструменту также требуется ряд настроек. По сути, для каждого типа файла, который мы будем собирать, понадобится отдельный загрузчик.
webpack и webpack-cli следуют тому же принципу, что и Babel. Первый является основным пакетом, а второй позволяет обращаться к нему через командную строку.
webpack-dev-server требуется нам для локальной разработки. Вы заметите, что package.json никогда не ссылается на него из скрипта, но он необходим для запуска webpack serve :
Последними идут загрузчики, нужные для разных файлов, которые мы будем обрабатывать. ts-loader также присутствует, но поскольку мы используем для компиляции JS-файлов Babel, фактичекски, он нам не понадобится.
В завершении, как и для Babel, нужно настроить файл конфигурации webpack.config.js :
React
Учитывая, что создаем мы приложение React, нам также нужны и соответствующие пакеты.
Этого будет достаточно:
В завершении настроим библиотеку управления состоянием.
Согласно документации нам нужно следующее:
Здесь мы подумаем наперед и добавим отдельный пакет, который используется при написании логики Kea в TypeScript:
package.json
После всей этой настройки нужно добавить в package.json пару скриптов:
start будет запускать сервер, а typegen генерировать типы для файлов логики Kea.
Наконец, сам код React
Нехило так настроечек? Думаю, что шаблоны определенно заслуживают благодарности, особенно, когда они берут на себя все управление зависимостями и версионирование (react-scripts).
Как бы то ни было, но с настройкой мы закончили, и пора заняться кодом.
Но сначала немного чистого HTML
Вот мой index.html :
Здесь происходит несколько действий:
Точка входа
Вот содержимое моего:
Здесь происходит три основных действия:
2. Мы импортируем и отрисовываем компонент App (который еще не собран).
3. Мы сообщаем React отрисовать приложение, используя div root из index.html в качестве «точки привязки».
Приложение!
Далее также внутри src/ создайте файл App.tsx со следующим содержимым:
Эти два дополнительных компонента я включил, чтобы убедиться в следующем:
Так что при желании вы можете на этом остановиться. Если же вы тоже хотите увидеть, как работают перечисленные возможности, то продолжим.
Написание JS и TS
Проблем не возникает, так как в webpack.config.js установлено это правило:
Чтобы убедиться в работоспособности этой схемы, я просто создал мелкий JS-компонент и импортировал его в приложение.
Counter
Последним я добавил в этот мини-проект традиционный React-компонент Counter.
Задачей было убедиться в работоспособности настроек Kea и в том, что при этом также работает импорт CSS-файлов.
1. index.tsx — содержит сам компонент:
3. style.css — здесь я использовал минимальную стилизацию просто, чтобы убедиться в правильной работоспособности CSS:
Вот и все!
Если вы добрались до этой части, то, надеюсь, на выходе вы получили свежеиспеченное приложение React, современный шаблон, а также некоторый багаж дополнительных знаний. Честно говоря, здесь я просто задокументировал часть своего процесса обучения, но и вы наверняка из этого что-нибудь да почерпнули!
Tutorial: Intro to React
This tutorial doesn’t assume any existing React knowledge.
Before We Start the Tutorial
We will build a small game during this tutorial. You might be tempted to skip it because you’re not building games — but give it a chance. The techniques you’ll learn in the tutorial are fundamental to building any React app, and mastering it will give you a deep understanding of React.
This tutorial is designed for people who prefer to learn by doing. If you prefer learning concepts from the ground up, check out our step-by-step guide. You might find this tutorial and the guide complementary to each other.
The tutorial is divided into several sections:
You don’t have to complete all of the sections at once to get the value out of this tutorial. Try to get as far as you can — even if it’s one or two sections.
What Are We Building?
In this tutorial, we’ll show how to build an interactive tic-tac-toe game with React.
You can see what we’ll be building here: Final Result. If the code doesn’t make sense to you, or if you are unfamiliar with the code’s syntax, don’t worry! The goal of this tutorial is to help you understand React and its syntax.
We recommend that you check out the tic-tac-toe game before continuing with the tutorial. One of the features that you’ll notice is that there is a numbered list to the right of the game’s board. This list gives you a history of all of the moves that have occurred in the game, and it is updated as the game progresses.
You can close the tic-tac-toe game once you’re familiar with it. We’ll be starting from a simpler template in this tutorial. Our next step is to set you up so that you can start building the game.
We’ll assume that you have some familiarity with HTML and JavaScript, but you should be able to follow along even if you’re coming from a different programming language. We’ll also assume that you’re familiar with programming concepts like functions, objects, arrays, and to a lesser extent, classes.
Setup for the Tutorial
There are two ways to complete this tutorial: you can either write the code in your browser, or you can set up a local development environment on your computer.
Setup Option 1: Write Code in the Browser
This is the quickest way to get started!
First, open this Starter Code in a new tab. The new tab should display an empty tic-tac-toe game board and React code. We will be editing the React code in this tutorial.
You can now skip the second setup option, and go to the Overview section to get an overview of React.
Setup Option 2: Local Development Environment
This is completely optional and not required for this tutorial!
Optional: Instructions for following along locally using your preferred text editor
This setup requires more work but allows you to complete the tutorial using an editor of your choice. Here are the steps to follow:
Don’t delete the entire src folder, just the original source files inside it. We’ll replace the default source files with examples for this project in the next step.
Now if you run npm start in the project folder and open http://localhost:3000 in the browser, you should see an empty tic-tac-toe field.
We recommend following these instructions to configure syntax highlighting for your editor.
If you get stuck, check out the community support resources. In particular, Reactiflux Chat is a great way to get help quickly. If you don’t receive an answer, or if you remain stuck, please file an issue, and we’ll help you out.
Now that you’re set up, let’s get an overview of React!
React is a declarative, efficient, and flexible JavaScript library for building user interfaces. It lets you compose complex UIs from small and isolated pieces of code called “components”.
React has a few different kinds of components, but we’ll start with React.Component subclasses:
We’ll get to the funny XML-like tags soon. We use components to tell React what we want to see on the screen. When our data changes, React will efficiently update and re-render our components.
Here, ShoppingList is a React component class, or React component type. A component takes in parameters, called props (short for “properties”), and returns a hierarchy of views to display via the render method.
The render method returns a description of what you want to see on the screen. React takes the description and displays the result. In particular, render returns a React element, which is a lightweight description of what to render. Most React developers use a special syntax called “JSX” which makes these structures easier to write. The
If you’re curious, createElement() is described in more detail in the API reference, but we won’t be using it in this tutorial. Instead, we will keep using JSX.
JSX comes with the full power of JavaScript. You can put any JavaScript expressions within braces inside JSX. Each React element is a JavaScript object that you can store in a variable or pass around in your program.
The ShoppingList component above only renders built-in DOM components like
Inspecting the Starter Code
If you’re going to work on the tutorial in your browser, open this code in a new tab: Starter Code. If you’re going to work on the tutorial locally, instead open src/index.js in your project folder (you have already touched this file during the setup).
This Starter Code is the base of what we’re building. We’ve provided the CSS styling so that you only need to focus on learning React and programming the tic-tac-toe game.
By inspecting the code, you’ll notice that we have three React components:
The Square component renders a single and the Board renders 9 squares. The Game component renders a board with placeholder values which we’ll modify later. There are currently no interactive components.
Passing Data Through Props
To get our feet wet, let’s try passing some data from our Board component to our Square component.
We strongly recommend typing code by hand as you’re working through the tutorial and not using copy/paste. This will help you develop muscle memory and a stronger understanding.
In Board’s renderSquare method, change the code to pass a prop called value to the Square:
Change Square’s render method to show that value by replacing*> with
After: You should see a number in each square in the rendered output.
Congratulations! You’ve just “passed a prop” from a parent Board component to a child Square component. Passing props is how information flows in React apps, from parents to children.
Making an Interactive Component
Let’s fill the Square component with an “X” when we click it. First, change the button tag that is returned from the Square component’s render() function to this:
If you click on a Square now, you should see ‘click’ in your browser’s devtools console.
As a next step, we want the Square component to “remember” that it got clicked, and fill it with an “X” mark. To “remember” things, components use state.
First, we’ll add a constructor to the class to initialize the state:
In JavaScript classes, you need to always call super when defining the constructor of a subclass. All React component classes that have a constructor should start with a super(props) call.
Now we’ll change the Square’s render method to display the current state’s value when clicked:
After these changes, the tag that is returned by the Square’s render method looks like this:
When you call setState in a component, React automatically updates the child components inside of it too.
The React Devtools extension for Chrome and Firefox lets you inspect a React component tree with your browser’s developer tools.
The React DevTools let you check the props and the state of your React components.
After installing React DevTools, you can right-click on any element on the page, click “Inspect” to open the developer tools, and the React tabs (“⚛️ Components” and “⚛️ Profiler”) will appear as the last tabs to the right. Use “⚛️ Components” to inspect the component tree.
However, note there are a few extra steps to get it working with CodePen:
Completing the Game
We now have the basic building blocks for our tic-tac-toe game. To have a complete game, we now need to alternate placing “X”s and “O”s on the board, and we need a way to determine a winner.
Lifting State Up
Currently, each Square component maintains the game’s state. To check for a winner, we’ll maintain the value of each of the 9 squares in one location.
We may think that Board should just ask each Square for the Square’s state. Although this approach is possible in React, we discourage it because the code becomes difficult to understand, susceptible to bugs, and hard to refactor. Instead, the best approach is to store the game’s state in the parent Board component instead of in each Square. The Board component can tell each Square what to display by passing a prop, just like we did when we passed a number to each Square.
To collect data from multiple children, or to have two child components communicate with each other, you need to declare the shared state in their parent component instead. The parent component can pass the state back down to the children by using props; this keeps the child components in sync with each other and with the parent component.
Lifting state into a parent component is common when React components are refactored — let’s take this opportunity to try it out.
Add a constructor to the Board and set the Board’s initial state to contain an array of 9 nulls corresponding to the 9 squares:
When we fill the board in later, the this.state.squares array will look something like this:
The Board’s renderSquare method currently looks like this:
In the beginning, we passed the value prop down from the Board to show numbers from 0 to 8 in every Square. In a different previous step, we replaced the numbers with an “X” mark determined by Square’s own state. This is why Square currently ignores the value prop passed to it by the Board.
Next, we need to change what happens when a Square is clicked. The Board component now maintains which squares are filled. We need to create a way for the Square to update the Board’s state. Since state is considered to be private to a component that defines it, we cannot update the Board’s state directly from Square.
Instead, we’ll pass down a function from the Board to the Square, and we’ll have Square call that function when a square is clicked. We’ll change the renderSquare method in Board to:
We split the returned element into multiple lines for readability, and added parentheses so that JavaScript doesn’t insert a semicolon after return and break our code.
After these changes, the Square component looks like this:
When a Square is clicked, the onClick function provided by the Board is called. Here’s a review of how this is achieved:
The DOM element’s onClick attribute has a special meaning to React because it is a built-in component. For custom components like Square, the naming is up to you. We could give any name to the Square’s onClick prop or Board’s handleClick method, and the code would work the same. In React, it’s conventional to use on[Event] names for props which represent events and handle[Event] for the methods which handle the events.
When we try to click a Square, we should get an error because we haven’t defined handleClick yet. We’ll now add handleClick to the Board class:
After these changes, we’re again able to click on the Squares to fill them, the same as we had before. However, now the state is stored in the Board component instead of the individual Square components. When the Board’s state changes, the Square components re-render automatically. Keeping the state of all squares in the Board component will allow it to determine the winner in the future.
Since the Square components no longer maintain state, the Square components receive values from the Board component and inform the Board component when they’re clicked. In React terms, the Square components are now controlled components. The Board has full control over them.
Why Immutability Is Important
In the previous code example, we suggested that you create a copy of the squares array using the slice() method instead of modifying the existing array. We’ll now discuss immutability and why immutability is important to learn.
There are generally two approaches to changing data. The first approach is to mutate the data by directly changing the data’s values. The second approach is to replace the data with a new copy which has the desired changes.
Data Change with Mutation
Data Change without Mutation
The end result is the same but by not mutating (or changing the underlying data) directly, we gain several benefits described below.
Complex Features Become Simple
Immutability makes complex features much easier to implement. Later in this tutorial, we will implement a “time travel” feature that allows us to review the tic-tac-toe game’s history and “jump back” to previous moves. This functionality isn’t specific to games — an ability to undo and redo certain actions is a common requirement in applications. Avoiding direct data mutation lets us keep previous versions of the game’s history intact, and reuse them later.
Detecting changes in mutable objects is difficult because they are modified directly. This detection requires the mutable object to be compared to previous copies of itself and the entire object tree to be traversed.
Detecting changes in immutable objects is considerably easier. If the immutable object that is being referenced is different than the previous one, then the object has changed.
Determining When to Re-Render in React
The main benefit of immutability is that it helps you build pure components in React. Immutable data can easily determine if changes have been made, which helps to determine when a component requires re-rendering.
You can learn more about shouldComponentUpdate() and how you can build pure components by reading Optimizing Performance.
We’ll now change the Square to be a function component.
Replace the Square class with this function:
We have changed this.props to props both times it appears.
When we modified the Square to be a function component, we also changed onClick= <() =>this.props.onClick()> to a shorter onClick=
We now need to fix an obvious defect in our tic-tac-toe game: the “O”s cannot be marked on the board.
We’ll set the first move to be “X” by default. We can set this default by modifying the initial state in our Board constructor:
Each time a player moves, xIsNext (a boolean) will be flipped to determine which player goes next and the game’s state will be saved. We’ll update the Board’s handleClick function to flip the value of xIsNext :
With this change, “X”s and “O”s can take turns. Try it!
Let’s also change the “status” text in Board’s render so that it displays which player has the next turn:
After applying these changes, you should have this Board component:
Declaring a Winner
Now that we show which player’s turn is next, we should also show when the game is won and there are no more turns to make. Copy this helper function and paste it at the end of the file:
We will call calculateWinner(squares) in the Board’s render function to check if a player has won. If a player has won, we can display text such as “Winner: X” or “Winner: O”. We’ll replace the status declaration in Board’s render function with this code:
We can now change the Board’s handleClick function to return early by ignoring a click if someone has won the game or if a Square is already filled:
Congratulations! You now have a working tic-tac-toe game. And you’ve just learned the basics of React too. So you’re probably the real winner here.
Adding Time Travel
As a final exercise, let’s make it possible to “go back in time” to the previous moves in the game.
Storing a History of Moves
If we mutated the squares array, implementing time travel would be very difficult.
However, we used slice() to create a new copy of the squares array after every move, and treated it as immutable. This will allow us to store every past version of the squares array, and navigate between the turns that have already happened.
Now we need to decide which component should own the history state.
Lifting State Up, Again
We’ll want the top-level Game component to display a list of past moves. It will need access to the history to do that, so we will place the history state in the top-level Game component.
First, we’ll set up the initial state for the Game component within its constructor:
Next, we’ll have the Board component receive squares and onClick props from the Game component. Since we now have a single click handler in Board for many Squares, we’ll need to pass the location of each Square into the onClick handler to indicate which Square was clicked. Here are the required steps to transform the Board component:
The Board component now looks like this:
We’ll update the Game component’s render function to use the most recent history entry to determine and display the game’s status:
Since the Game component is now rendering the game’s status, we can remove the corresponding code from the Board’s render method. After refactoring, the Board’s render function looks like this:
Unlike the array push() method you might be more familiar with, the concat() method doesn’t mutate the original array, so we prefer it.
At this point, the Board component only needs the renderSquare and render methods. The game’s state and the handleClick method should be in the Game component.
Showing the Past Moves
Since we are recording the tic-tac-toe game’s history, we can now display it to the player as a list of past moves.
We learned earlier that React elements are first-class JavaScript objects; we can pass them around in our applications. To render multiple items in React, we can use an array of React elements.
In JavaScript, arrays have a map() method that is commonly used for mapping data to other data, for example:
Using the map method, we can map our history of moves to React elements representing buttons on the screen, and display a list of buttons to “jump” to past moves.
Let’s map over the history in the Game’s render method:
As we iterate through history array, step variable refers to the current history element value, and move refers to the current history element index. We are only interested in move here, hence step is not getting assigned to anything.
Warning: Each child in an array or iterator should have a unique “key” prop. Check the render method of “Game”.
Let’s discuss what the above warning means.
When we render a list, React stores some information about each rendered list item. When we update a list, React needs to determine what has changed. We could have added, removed, re-arranged, or updated the list’s items.
Imagine transitioning from
When a list is re-rendered, React takes each list item’s key and searches the previous list’s items for a matching key. If the current list has a key that didn’t exist before, React creates a component. If the current list is missing a key that existed in the previous list, React destroys the previous component. If two keys match, the corresponding component is moved. Keys tell React about the identity of each component which allows React to maintain state between re-renders. If a component’s key changes, the component will be destroyed and re-created with a new state.
It’s strongly recommended that you assign proper keys whenever you build dynamic lists. If you don’t have an appropriate key, you may want to consider restructuring your data so that you do.
If no key is specified, React will present a warning and use the array index as a key by default. Using the array index as a key is problematic when trying to re-order a list’s items or inserting/removing list items. Explicitly passing key= silences the warning but has the same problems as array indices and is not recommended in most cases.
Keys do not need to be globally unique; they only need to be unique between components and their siblings.
Implementing Time Travel
In the tic-tac-toe game’s history, each past move has a unique ID associated with it: it’s the sequential number of the move. The moves are never re-ordered, deleted, or inserted in the middle, so it’s safe to use the move index as a key.
First, add stepNumber: 0 to the initial state in Game’s constructor :
Notice in jumpTo method, we haven’t updated history property of the state. That is because state updates are merged or in more simple words React will update only the properties mentioned in setState method leaving the remaining state as is. For more info see the documentation.
We will now make a few changes to the Game’s handleClick method which fires when you click on a square.
The stepNumber state we’ve added reflects the move displayed to the user now. After we make a new move, we need to update stepNumber by adding stepNumber: history.length as part of the this.setState argument. This ensures we don’t get stuck showing the same move after a new one has been made.
Finally, we will modify the Game component’s render method from always rendering the last move to rendering the currently selected move according to stepNumber :
If we click on any step in the game’s history, the tic-tac-toe board should immediately update to show what the board looked like after that step occurred.
Congratulations! You’ve created a tic-tac-toe game that:
Nice work! We hope you now feel like you have a decent grasp of how React works.
Check out the final result here: Final Result.
If you have extra time or want to practice your new React skills, here are some ideas for improvements that you could make to the tic-tac-toe game which are listed in order of increasing difficulty:
Введение в React
Здесь подключаются библиотеки React и React-dom, а также компилятор babel.
Babel не является обязательным для использования React, но полезным для написания кода UI, с помощью JSX.
Шаг 2 Добавьте пустой контейнер на вашу страницу чтобы отметить место, где вы хотите что-либо отобразить с помощью React.
Шаг 3 Теперь вы можете использовать React вместе с JSX в любом теге script, добавив к нему атрибут type=«text/babel».
1.2.2 Добавление React с помощью create-react-app
Инструменты, используемые для разработки React, опираются на Node.js, поэтому первое что вам необходимо сделать, это установить Node, что бы использовать npm.
Пакет create-react-app является стандартным способом создания и управления сложными пакетами React и предоставляет разработчикам полный набор инструментов. Используйте create-react-app, для создания нового React приложения.
После установки nodejs, для установки create-react-app:
Выбор за вами какой инструмент использовать (npx, npm, yarn) для создания React приложения.
Выполнение любой из этих команд создаст каталог с именем my-app внутри текущей папки. Внутри этого каталога будет сгенерирована исходная структура проекта и установлены необходимые зависимости:
Для запуска приложения в режиме разработки перейдите в папку с вашим приложением и выполните npm start или yarn start:
Страница автоматически перезагрузится, если вы внесете изменения в код. Вы увидите ошибки сборки и предупреждения в консоли. Откройте localhost:3000, чтобы просмотреть приложение в браузере.
Обратите внимание! Для сборки проекта эти файлы должны существовать с точными именами файлов:
2. Basically React
2.1 React object
React — это точка входа в библиотеку React. При подключении React с помощью тега script, API верхнего уровня доступны в глобальном объекте React, а если вы используете ES6 и create-react-app, вы должны импортировать React объект:
Если же вы используете ES5 и create-react-app, вы можете импортировать React объект следующем образом:
В этой статье я использую синтаксис ES6 и буду предполагать, что вы тоже его используете. В противном случае советую прочитать соответствующий раздел документации: React без ES6.
2.2 React element
React элемент — минимальная единица React-приложения, объект описывающий то, что вы хотите увидеть на странице. Элементы React не изменяемые (immutable). То есть состояние элементов React не может быть изменено после создания.
Для создания React элементов вам нужно использовать методы createElement() или
createFactory(). Последний считается устаревшим и его использование не рекомендуется поэтому не будем останавливаться на нём. Если вы используете JSX, то вам не придётся вызывать данные методы.
React предоставляет методы для клонирования — cloneElement, проверки — isValidElement() и работой с структурой данных props.children это React.Children (семейство методов React.Children).
Для отображения React элементов необходимо вызвать метод Render объекта ReactDom. После отображения (рендеринга) React элемента вы не можете изменить его потомков или атрибуты. Единственным решением является повторный вызов ReactDom.render(). На практике не советуется повторный вызов этого метода. Поэтому для интерактивных элементов вам необходимо использовать React компоненты.
С помощью React элементов проще описать, как интерфейс выглядит в конкретный момент, чем-то как он изменяется с течением времени. К тому же такой подход позволяет избавиться от целого класса ошибок.
В React элементах допустимо использование встраиваемых выражений Javascript.
Пример использования встраиваемого выражения:
Если вы не используете JSX, то вы можете использовать встраиваемые выражения передав их как один из аргументов методу createElement.
Пример использования встраиваемого выражения с методом createElement:
2.2.1 React.createElement
Для создания React элемента используйте метод createElement:
Если же вы используете JSX, то у вас нет необходимости в специальных методах для создания React элемента.
Создание React элемента с использованием JSX:
Как вы могли заметить оба примера создают один и тот же объект. Таким образом из примера выше можно сделать вывод о том, что каждый элемент JSX это просто синтаксический сахар для вызова React.createElement().
Вы можете проверить это сами. Используя для этого онлайн компилятор Babel.
2.2.2 React.cloneElement
React.cloneElement — метод позволяющий клонировать React элементы.
Возвращает новый React элемент, используя переданный React элемент в качестве отправной точки. Аргументы такие же как у React.createElement() за исключением того, что первый параметр не имя нового тэга, а имеющиеся React элемент. Полученный элемент будет иметь пропсы исходного элемента, а новые пропсы будут поверхностно слиты воедино. Новые дочерние элементы заменят существующие. key и ref из исходного элемента будут сохранены.
2.2.3 React.isValidElement
React.isValidElement(object) — Проверяет, что объект является элементом React. Возвращает true в случае если объект является элементом React или false в случае если он не является элементом React.
2.2.4 React.Children
React.Children предоставляет функции для работы с непрозрачной структурой данных this.props.children. Если проще, то props.children это то, что вы включаете между открывающим и закрывающим тегами при вызове компонента.
Таким образом props.children может помочь сделать ваши компоненты React более гибкими и многократно используемыми. Вы можете использовать props.children для компонентов, которые представляют «общие блоки» и которые «не знают своих детей раньше времени». То есть в примере выше компонент Chill это шаблон, который можно использовать многократно с разным результатом. Конечно такой упрощенный пример сильно напоминает использование пропсов, но с помощью props.children вы можете строить более сложные структуры данных.
Давайте в вкратце рассмотрим методы для работы с props.children.
Похож на Array.prototype.map(). Создаёт новый массив с результатом вызова указанной функции для каждого элемента массива. Вызывает функцию для каждого непосредственного потомка, содержащегося в children передавая их по очереди в thisArg. Если children — это массив, он будет пройден, и функция будет вызвана для каждого потомка в массиве. Если children равен null или undefined, этот метод вернёт null или undefined, а не массив. Если children — это React.Fragment, он будет рассматриваться как целый потомок, а элементы внутри не будут пройдены. Метод map вызывает переданную функцию callback один раз для каждого элемента, в порядке их появления и конструирует новый массив из результатов её вызова.
Похож на Array.prototype.forEach(). Выполняет указанную функцию один раз для каждого элемента в массиве. В отличие от React.Children.map не возвращает массив из результатов вызова функции. Возвращает ubdefined.
Вы множите найти больше примеров тут и тут.
2.3 React компоненты
React компонент — функция возвращающая React-элемент или JavaScript класс реализующий метод render() который возвращает React-элемент. Соответственно компоненты, объявленные с помощью JavaScript функции принято называть «функциональными компонентами» а компоненты, объявленные с помощью JavaScript классов принято называть «классовыми компонентами».
Компоненты, объявленные как функции JavaScript не могут содержать «состояния», поэтому их также принято называть stateless components, то есть, компоненты без состояния, а компонентные объявленные как JavaScript класс могу содержать «состояние», поэтому их называют statefull components, то есть, компоненты с состоянием. *На самом деле вы можете добиться похожей функциональности и от функциональных компонентов используя хуки.
Классовые React-компоненты могут быть объявлены путём создания подклассов React.Component или React.PureComponent. Последний отличается лишь тем, что он реализует метод shouldComponentUpdate() (см. жизненный цикл компонентов).
Функциональный React-компонент это функция JavaScript, которая может быть обернута в React.memo. React.memo похож на React.PureComponent только предназначен для функциональных компонентов.
Пропсы — это просто аргументы передоверяемые компоненту. Когда React встречает JSX-атрибуты он собирает их в один объект и передаёт компоненту. Этот объект и называется «пропсы» (props).
Пример использования пропсов в функциональном компоненте:
Запомните! Названия типов пользовательских компонентов должны начинаться с большой буквы.
React-компоненты обязаны вести себя как чистые функции по отношению к своим пропсам.
Компонент никогда не должен что-то записывать в свои пропсы — вне зависимости от того, функциональный он или классовый.
2.3.1 React.Component
React.Component — это базовый класс для компонентов React. Для создания React-компонента наследуйте свойства и методы от React.Component:
Каждый компонент имеет методы жизненного цикла, которые закономерно вызываются при монтировании, обновление и размонтировании компонента. Переопределение такого метода позволяет выполнять код на конкретном этапе этого процесса. (см. 2.3.5 Lifecycle).
2.3.2 React.Fragment
Как вы могли заметить любой React элемент и компонент должен возвращать только один узел (один html тэг). Если же вам необходимо отрендерить несколько тегов, то они в обязательном порядке должны быть обернуты в один контейнер иначе вы получите ошибку. Но что же делать, если не хочется создавать лишние контейнеры? Ответ: React.Fragment.
Компонент React.Fragment позволяет возвращать несколько элементов в методе render() без создания дополнительного элемента DOM:
Конечно, если вы не используете Jsx, то ваш код будет выглядеть так:
В React v16.2.0 завезли новый синтаксический сахар для React.Fragment, с этой версии вы можете просто писать пустой html тэг, который будет оборачиваться в React.Fragment:
2.3.3 State
Состояние компонента (State) — это приватное свойство (state) классовых React компонентов. Обновляя состояние с помощью метода setState() компонент рендерится повторно. Из этого следует запомнить что компонент не будет рендерится заново если изменять состояние напрямую (без вызова setState()).
Давайте рассмотрим простейшей пример с кнопкой счетчиком. В этом примере при нажатии на кнопку вызывается метод incrementCount который с помощью setState обновляет состояние компонента и компонент рендерится снова, отображая новое значение счетчика.
Давайте разберём код по частям.
Ключевое слово super() используется как функция, вызывающая родительский конструктор. Её необходимо вызвать до первого обращения к ключевому слову this в теле конструктора. Поэтому прежде чем инициализировать начальное состояние компонента необходимо вызвать super(). Классовые компоненты всегда должны вызывать базовый конструктор с аргументом props. Даже если вы не используете пропсы.
Для методов необходимо вызывать метод bind() который наследуется из Function.prototype.bind() он создаёт новую функцию, которая при вызове устанавливает в качестве контекста выполнения this предоставленное значение. Это нужно потому что методы класса в JavaScript по умолчанию не привязаны к контексту. Поэтому this будет undefined в момент вызова функции если не привязать ее к контексту. Есть способ позволяющий избежать вызова bind(), это использование синтаксиса общедоступных полей классов:
С помощью ключевого слова onClick регистрируется обработчик событий вызывающий метод incrementCount каждый раз, когда совершается событие. Особенности обработки событий на React будут рассмотрены в следующей главе.
setState() использует текущее значение состояния для его обновления. Поэтому вместо объекта с новым состоянием передаётся функция получающая текущее состояние как аргумент. Дело в том что вызовы setState являются асинхронными из за чего this.state в некоторых случаях может отображать неправильное значение. Для понимания этого давайте взглянем на синтаксис метода setState:
setState() напоминает функцию fetch() делающая запрос. Метод setState() не всегда обновляет компонент сразу. Он может группировать или откладывать обновление до следующего раза. Это делает чтение this.state сразу после вызова setState() потенциальной ловушкой. Первый аргумент функции updater имеет следующий вид:
здесь state — ссылка на состояние компонента при изменении. Как state, так и props, полученные функцией, гарантированно будут обновлены. Второй параметр в setState() — дополнительный колбэк, который выполняется после того, как исполнится setState и произойдёт повторный рендер компонента. Если же следующее состояние не зависит от текущего тогда в качестве первого аргумента вы можете просто передать объект с новым состоянием.
Обновления состояния объединяются!
Если состояние хранит несколько значений, то изменение одно значения не повлияет на другое.
Оба поля можно обновить по отдельности с помощью отдельных вызовов setState()
Состояния объединяются поверхностно, поэтому вызов changeValue_1() оставляет value_2 нетронутым, но полностью заменяет value_1.
Состояние доступно только для самого компонента и скрыто от других. То есть this.state является приватным свойством.
Компонент может передать своё состояние вниз по дереву в виде пропсов дочерних компонентов.
2.3.4 Events
Обработка событии в React похожа на таковую в DOM-элементах за исключением синтаксических особенностей и некоторых особенностей реализации.
В React нельзя предотвратить события по умолчанию вернув false из обработчика события. Для этого нужно вызвать preventDefault().
Обработчики событий также получают объект Event, который в React называют SyntheticEvent. После вызова обработчика события объект SyntheticEvent повторно используется, а все его свойства будут очищены, поэтому нельзя использовать синтетические события асинхронно.
Но если же вы всё таки хотите использовать события асинхронно то вызывайте event.persist() на событии. Тогда оно будет извлечено из пула, что позволит вашему коду удерживать ссылки на это событие.
Список всех поддерживаемых событий вы можете посмотреть тут.
2.3.5 Lifecycle
Каждый компонент имеет несколько «методов жизненного цикла». Переопределение такого метода позволяет выполнять код на конкретном этапе этого процесса. Давайте рассмотрим все три этапа и разберёмся в какой последовательности, какие методы вызываются на различных этапах. И собственно, как вы можете использовать эти методы.
При монтирований (создание экземпляра компонента и его вставке в DOM) закономерно вызываются следующие методы в указанном порядке:
Конструктор — самый первый метод жизненного цикла, вызывается до того, как компонент будет примонтирован.
Собственно, конструктор вам скорее всего будет нужен для инициализации внутреннего состояния и привязки обработчиков событий к экземпляру. Следовательно, если вы не определяете состояние или не привязываете методы, то реализация конструктора вам не нужна.
Как правильно определять состояние и привязывать методы к контексту в конструкторе я уже детально объяснил. (см. 2.3.3 State).
getDerivedStateFromProps вызывается непосредственно перед вызовом метода render, как при начальном монтировании, так и при последующих обновлениях. Он должен вернуть объект для обновления состояния или null, чтобы ничего не обновлять. Этот метод существует для редких случаев, когда состояние зависит от изменений в пропсах. getDerivedStateFromProps существует только для одной цели. Он позволяет компоненту обновлять свое внутреннее состояние в результате изменений в props. Для лучшего понимания прочитайте статью Brian Vaughn, You Probably Don’t Need Derived State.
Так как это статический метод, он не имеет доступа к экземпляру компонента. Чтобы использовать пропсы, состояние и методы класса в getDerivedStateFromProps(), их нужно вынести за пределы класса в виде чистых функций.
Если вы хотите повторно использовать код между getDerivedStateFromProps() и другими методами класса, извлеките чистые функции пропсов и состояния компонента и поместите их вне определения класса.
Обратите внимание, что этот метод запускается при каждом рендере, независимо от причины.
При вызове он проверяет this.props и this.state и возвращает один из следующих вариантов:
Взаимодействовать с браузером необходимо в componentDidMount() или других методах жизненного цикла. Чистый render() делает компонент понятным.
В отличие от других методов жизненного цикла, он является единственным обязательным методом в классовом компоненте.
componentDidMount() вызывается сразу после монтирования (то есть, вставки компонента в DOM). В этом методе должны происходить действия, которые требуют наличия DOM-узлов. Например, работа с анимацией или создание сетевых запросов.
Вы можете сразу вызвать setState() в componentDidMount(). Это вызовет дополнительный рендер перед тем, как браузер обновит экран. Гарантируется, что пользователь не увидит промежуточное состояние, даже если render() будет вызываться дважды. Правда при таком подходе возможны проблемы с производительностью. Начальное состояние лучше объявить в constructor(). Однако, это может быть необходимо для случаев, когда нужно измерить размер или положение DOM-узла, на основе которого происходит рендер. Например, для модальных окон или всплывающих подсказок.
Если монтирование происходит при создании экземпляра компонента и его рендеринге (передаче компонента в метод ReactDom.render()), то обновление происходит при последующих вызовах ReactDom.render(). Обновление происходит при изменении пропсов или состояния компонента. При повторном рендере компонента закономерно вызываются следующие методы в указанном порядке:
Если ваш метод render() зависит от некоторых других данных, вы можете указать React необходимость в повторном рендере, вызвав forceUpdate().
Вызов forceUpdate() приведёт к выполнению метода render() в компоненте, пропуская shouldComponentUpdate(). Это вызовет обычные методы жизненного цикла для дочерних компонентов, включая shouldComponentUpdate() каждого дочернего компонента. React по-прежнему будет обновлять DOM только в случае изменения разметки.
В этом примере при нажатие на кнопку будет вызван handleClick который приведёт к обновлению компонента и вызову getSnapshotBeforeUpdate в Tittle который изменит значение свойства button.click перед тем как компонент будет отображён. В итоге при каждом нажатии кнопки надпись в Title будет сменятся.
Конечно это можно было реализовать проще, просто изменяя состояние Clicker в handleClick и передовая его как props в Tittle. Но этот пример хорошо демонстрирует работу forceUpdate(). Можно сказать, что forceUpdate() это замена для setState() когда необходимо принудительно обновить компонент. Вы можете использовать этот метод в двух случаях: когда вы не хотите реализовывать состояние компонента но хотите иметь способ принудительного обновления либо если вы хотите пропустить shouldComponentUpdate() при обновление компонента.
Метод getDerivedStateFromProps() уже был рассмотрен выше так как он вызывается как при начальном монтировании, так и при обновлении компонента. Не ясно для чего он вызывается при монтировании. Поскольку его основной задачей по задумке разработчиков это возвращение объекта для обновления состояния или null, чтобы ничего не обновлять.
shouldComponentUpdate указывает на необходимость следующего рендера на основе изменений состояния и пропсов. По умолчанию происходит повторный рендер при любом изменении состояния. В большинстве случаев вы должны полагаться на это поведение. Но бывают специфические случае, когда, к примеру, необходимость в обновление компонента возникает только при изменение конкретного props или state, а во всех остальных случаях не требуется. Вы можете сравнить this.props с nextProps, а this.state с nextState, верните false чтобы пропустить обновление React.
Обратите внимание возврат false не предотвращает повторный рендер дочерних компонентов при изменении их состояния.
Значение по умолчанию равно true. Этот метод не вызывается при первом рендере или когда используется forceUpdate().
Поскольку лишние вызовы ReactDom.render() могут плохо сказаться на скорости работы вашего приложения, этот метод нужен только для повышения производительности. Не опирайтесь на возможность shouldComponentUpdate() «предотвратить» рендер, это может привести к багам.
Как говорилось ранее (см. 2.3 React компоненты) классовые React-компоненты которые объявляются путём создания подкласса React.PureComponent, а не React.Component по умолчанию реализуют метод shouldComponentUpdate().
Метод shouldComponentUpdate() базового класса React.PureComponent делает только поверхностное сравнение объектов. Если они содержат сложные структуры данных, это может привести к неправильной работе для более глубоких различий (то есть, различий, не выраженных на поверхности структуры). Наследуйте класс PureComponent только тогда, когда вы ожидаете использовать простые пропсы и состояние, или используйте forceUpdate(), когда знаете, что вложенные структуры данных изменились.
При обновление сразу после shouldComponentUpdate() вызывается render() принцип работы которого рассматривался выше.
getSnapshotBeforeUpdate() вызывается прямо перед этапом «фиксирования» (например, перед добавлением в DOM). Он позволяет вашему компоненту брать некоторую информацию из DOM (например, положение прокрутки) перед её возможным изменением. Любое значение, возвращаемое этим методом жизненного цикла, будет передано как параметр componentDidUpdate().
Хотя этот метод и вызывается после render() в нем вы все еще можете получить «снимок», то как выглядит DOM до рендера.
Значение снимка (или null) должно быть возвращено из этого метода.
componentDidUpdate() вызывается сразу после обновления DOM. Он подходит для выполнения, таких действии которые требуют наличие DOM. Также он подходит для выполнения сетевых запросов, которые выполняются на основании результата сравнения текущих пропсов с предыдущими. Если пропсы не изменились, новый запрос может и не требоваться.
В componentDidUpdate() можно вызывать setState(), однако его необходимо обернуть в условие, чтобы не возникла бесконечная рекурсия.
В тех редких случаях когда реализован метод жизненного цикла getSnapshotBeforeUpdate(), его результат передаётся componentDidUpdate() в качестве третьего параметра snapshot.
componentDidUpdate() не вызывается, если shouldComponentUpdate() возвращает false.
При удалении компонента из DOM вызывается метод componentWillUnmount().
componentWillUnmount() вызывается непосредственно перед размонтированием (например при вызове ReactDOM.unmountComponentAtNode()) и удалением компонента. В этом методе выполняется необходимый сброс: отмена таймеров, сетевых запросов и подписок, созданных ранее.
2.3.6 Refs
Рефы дают возможность получить доступ к DOM-узлам или React-элементам, созданным в рендер-методе. Обычно родительские компоненты могут взаимодействовать с дочерними только через пропсы, но иногда вам требуется императивно изменить дочерний элемент, обойдя обычный поток данных. Рефы как небольшие лазейки, которые позволяют вам обойти семантику React в тех случаях, когда обычным способом достичь требуемой функциональности невозможно. Из-за чего в случаях, когда задачу можно решить декларативным способом вы должны избегать использования рефов.
Ситуации, в которых использования рефов является оправданным:
Когда атрибут ref используется с классовым компонентом, свойство current объекта-рефа получает экземпляр смонтированного компонента.
В этом примере this.ref это ссылка на дом элемент h1 — Hello world. При нажатии на кнопку вызывается функция handleClick использующая ссылку на h1 через ref и рандомно изменяет цвет текста.
Узнайте больше о Рефах здесь.
2.4 ReactDOM
Если объект React из react предоставляет API для создания и произведения различных манипуляции над React объектами и компонентами, то ReactDom предоставляет API для рендеринга этих компонентов или объектов.
Под рендерингом понимается отображение элементов или компонентов на странице.
Методы, предоставляемые пакетом ReactDom:
2.4.1 Render
Рендерит React-элемент в DOM-элемент, переданный в аргумент container и возвращает ссылку на корневой экземпляр ReactComponent или null для компонентов без состояния.
Любые существующие дочерние элементы DOM container заменяются при первом вызове.
Другими словами — если вы рендерите в DOM узел, заведомо имеющий какие-либо дочерние элементы, то они будут удалены и заменены на element.
Повторный вызов произведёт обновление контейнера и изменит соответствующую часть DOM, чтобы она содержала последние изменения.
Если дополнительно был предоставлен колбэк, он будет вызван после того, как компонент отрендерится или обновится.
2.4.2 Hydrate
Тоже самое что и ReactDOM.render но для случаев, когда рендеринг на клиенте основан на результатах серверного рендеринга. Что такое Server-Side Rendering я объяснять не собираюсь. Для этого уже написана отдельная статья и соответсвующий раздел документации ReactDOMServer.
React ожидает, что отрендеренное содержимое идентично на сервере, и на клиенте. Текстовые различия в контенте могут быть переписаны поверх, но вам следует рассматривать такие нестыковки как ошибки и исправлять их.
Если атрибут отдельного элемента или текстовое содержимое неизбежно отличается на сервере и клиенте (например, отметка времени), вы можете отключить предупреждение, добавив к элементу suppressHydrationWarning=
2.4.3 UnmountComponentAtNode
Удаляет смонтированный компонент из container и очищает его обработчики событий и состояние. Если в контейнер не было смонтировано ни одного компонента, вызов этой функции ничего не делает. Возвращает true, если компонент был размонтирован, и false если нет компонента для размонтирования. Не перепутайте, container это не React элемент который необходимо удалить, а DOM узел в котором находится компонент.
2.4.4 CreatePortal
Порталы позволяют рендерить дочерние элементы в DOM-узел, который находится вне DOM-иерархии родительского компонента.
child — это любой React-компонент, который может быть отрендерен
container — это ссылка на DOM-элемент.
Что бы понять принцип действия порталов давайте рассмотрим простой пример:
Теперь используя портал, можно изменить то куда будет отрендерин компонент, точнее часть компонента:
Перехват событий, всплывающих от портала к родительскому компоненту, позволяет создавать абстракции, которые не спроектированы специально под порталы. Например, вы отрендерили некий дочерний элемент. Тогда его события могут быть перехвачены родительским компонентом, вне зависимости от того, был ли этот дочерний элемент реализован с использованием порталов или без них. То есть, не смотря на то где находятся дети, родительский компонент все равно будет перехватывать события даже с учётом того что в html он и не является родительским благодаря использованию порталов.
3. Other topics
Здесь будут рассмотрены прочие темы, которые на мой взгляд не относятся к базовым понятиям React. В общем то прочитав первые два пункта 1. Getting started with React и 2. Basically React вы уже будете обладать достаточными знаниями для начала работы с React.
3.1 Lists and Keys
Одной из целей, которые преследовали авторы при разработке React это многократное использование встроенных интерфейсов. Поэтому компоненты могут напоминать шаблоны для интерфейсов. Компоненты, написанные разными людьми, должны хорошо работать вместе. Этот патерн принято называть композиция (en. Composition).
Одной из таких концепции является использование списков. Например, вы множите определить общий шаблон для списка друзей пользователя в мессенджере или списка покупок в интернет магазине и отображать такой персонализированный список для каждого пользователя.
Давайте рассмотрим простой пример: у нас есть список друзей пользователя, который мы хотим отобразить в сайдбар. Мы можем сделать это следующим образом:
В главе 2.3.5 Lifecycle при рассмотрение метода render() вы узнали, что данный метод может возвращать не только React элементы или компоненты, но также и массивы, фрагменты, порталы, строки, числа, Booleans или null. Таким образом вы можете вернуть массив пользователей, состоящий из элементов React. Это конечно удобно, но при возвращении массива из компонента, вы получите следующее предупреждение:
Warning: Each child in a list should have a unique «key» prop.
У каждого ребенка в списке должно быть уникальное свойство «key».
Key это специальный строковый атрибут, который нужно указывать при создании списка элементов. Он нужен для оптимизации работы React при изменении DOM с течением времени. Для большего понимания работы React при изменение DOM прочитайте статью Алгоритм сравнения. Ключи должны быть уникальны в пределах одного списка элементов. Если переписать компонент с использованием Key то он будет выглядеть следующим образом:
3.2 Error Handling
При разработке больших приложений могут возникать трудности с обнаружением и исправлением целого ряда различных ошибок, например, ошибок проектирования, логических или синтаксических ошибок. Для этого в React есть различные средства, которые призваны помочь разработчикам в поиске и исправлений таких ошибок.
Ошибка JavaScript где-то в коде UI не должна прерывать работу всего приложения. Для этого были добавлены специальные методы отлавливающие ошибки JavaScript в любом месте деревьев их дочерних компонентов, для сохранения их в журнале ошибок и вывода запасного UI вместо рухнувшего дерева компонентов. Они отлавливают ошибки при рендеринге, в методах жизненного цикла и конструкторах деревьев компонентов, расположенных под ними. Объекты реализующие такие методы принято называть «Предохранители». Вы можете узнать больше о предохранителях в специальном разделе документации Error Boundaries. Работают они следующем образом: если возникают ошибки в дочерних элементах предохранителей, они вызывают специальные методы и рендерят запасной вариант вместо рухнувшего интерфейса.
JavaScript язык с динамической типизации. Такой вариант типизации сильно облегчает работу для программистов, но может привести к сложным ошибкам. Инструменты для статической типизации, такие как Flow или TypeScript, позволяют отлавливать большую часть таких ошибок ещё до исполнения кода. Кроме того, они существенно улучшают процессы разработки, добавляя авто дополнение и другие возможности. Для использования статической типизации при написании React приложений прочитайте соответствующий раздел документации Static Type Checking.
Но даже если вы не используете расширения вроде Flow и TypeScript React предоставляет встроенные возможности для проверки типов. Это проверка типов с помощью PropTypes. Для проверки на правильность переданных типов данных в пропсы компонента вам нужно использовать специальное свойство propTypes:
При этом если вместо строки передать число (как показано выше), то в консоле можно будет увидеть следующее предупреждение: Warning: Failed prop type: Invalid prop `name` of type `number` supplied to `PropTypesExample`, expected `string`.
С версии React 15.5 React.PropTypes были вынесены в отдельный пакет. Так что используйте библиотеку prop-types
Также для обнаружения потанцеальных проблем вам может помочь Строгий режим (StrictMode). Также, как и Fragment, StrictMode не рендерит видимого UI. Строгий режим активирует дополнительные проверки и предупреждения для своих потомков.
Используйте библиотеку React Testing Library для написания тестов. В качестве альтернативы используйте утилиту тестирования Enzyme, которая легко позволяет делать проверки, управлять, а также просматривать выходные данные React-компонентов. Также прочитайте специальный раздел документации React (Testing) что бы знать больше о тестах.
3.2.1 getDerivedStateFromError
Этот метод жизненного цикла вызывается после возникновения ошибки у компонента-потомка. Он получает ошибку в качестве параметра и возвращает значение для обновления состояния.
Стоит отметить места, в которых данные методы не отловят ошибки: в обработчиках событий, асинхронном коде, серверном рендеринге, самом предохранителе. Поэтому если ошибка произойдет в дочернем компоненте, то она будет отловлена и вызваны методы static getDerivedStateFromError() и componentDidCatch().
Начиная с React 16, ошибки, не отловленные ни одним из предохранителей, будут приводить к размонтированию всего дерева компонентов React.
3.2.2 componentDidCatch
Этот метод также, как и getDerivedStateFromError отвечает за обработку ошибок и вызывается сразу после getDerivedStateFromError. Если предназначение getDerivedStateFromError это вернуть значение для обновления состояния, то предназначение componentDidCatch это логирование ошибок. То есть в componentDidCatch вы должны писать код для журналирования информации об отловленной ошибке.
Этот метод получает два параметра:
error — перехваченная ошибка
info — объект с ключом componentStack, содержащий информацию о компоненте, в котором произошла ошибка.
Дополняя предыдущий пример методом componentDidCatch получаем следующий код:
Методы console были добавлены только для того то бы показать из чего состоят объекты ошибки. В консоле получаем следующее:
Заключение
Спасибо что прочитали мою статью «Введение в React». Эта статья затрагивает основные (и не только) темы и концепции React. После прочтения данной статьи вы будете обладать хорошим фундаментом теоретических знаний о React которых будет достаточно для грамотного начала вашего первого проекта. Я надеюсь, что эта статья поможет вам в освоении React’а. Конечно для разработки настоящих проектов знаний одного только React вам будет явно недостаточно. Вы скорее всего будете использовать кучу других библиотек и пакетов для написания более сложных интерфейсов. Да и для того что бы облегчить себе работу (зачем изобретать велосипед) если кто-то уже его изобрёл. Скорее всего вы будете использовать Redux для лучшей работы с хранилищем, React Router для обеспечения URL-маршрутизации, Axios для выполнения асинхронных HTTP-запросов, GraphQL JS удобный язык запросов для API, а также огромное количество других API. Пишите в комментариях какие библиотеки используете вы.
Огромное количество Hooks API для React из GitHub.
Hello World
The smallest React example looks like this:
It displays a heading saying “Hello, world!” on the page.
Click the link above to open an online editor. Feel free to make some changes, and see how they affect the output. Most pages in this guide will have editable examples like this one.
How to Read This Guide
In this guide, we will examine the building blocks of React apps: elements and components. Once you master them, you can create complex apps from small reusable pieces.
This guide is designed for people who prefer learning concepts step by step. If you prefer to learn by doing, check out our practical tutorial. You might find this guide and the tutorial complementary to each other.
This is the first chapter in a step-by-step guide about main React concepts. You can find a list of all its chapters in the navigation sidebar. If you’re reading this from a mobile device, you can access the navigation by pressing the button in the bottom right corner of your screen.
Every chapter in this guide builds on the knowledge introduced in earlier chapters. You can learn most of React by reading the “Main Concepts” guide chapters in the order they appear in the sidebar. For example, “Introducing JSX” is the next chapter after this one.
Knowledge Level Assumptions
React is a JavaScript library, and so we’ll assume you have a basic understanding of the JavaScript language. If you don’t feel very confident, we recommend going through a JavaScript tutorial to check your knowledge level and enable you to follow along this guide without getting lost. It might take you between 30 minutes and an hour, but as a result you won’t have to feel like you’re learning both React and JavaScript at the same time.
This guide occasionally uses some newer JavaScript syntax in the examples. If you haven’t worked with JavaScript in the last few years, these three points should get you most of the way.
Let’s Get Started!
Keep scrolling down, and you’ll find the link to the next chapter of this guide right before the website footer.
Learning React With Create-React-App (Part 1)
Last Updated: 11/17/2017
Current Versions
Introduction
If you’ve been reading up on web technologies lately, then odds are you’ve heard of/read about/learned React.js already. One of the major complaints that was always repeated about React was how difficult it was to get started building an application. There are, of course, ways around this. First, you could just use a CDN link to React inside of your webpage and instantly have the ability to use React, but without some other niceties that come with a proper React development environment. Learning Webpack/Brunch/Browserify/etc, however, is often a non-starter for people who want to start working with React in a more modern way (using JSX and ES6, for example, which is totally worth the effort!).
So, what’s a web developer to do when faced with the cliff of Webpack/Babel/Brunch/NPM/Node/React? Simple, just use create-react-app!
And any code blocks will look like this:
Updates To create-react-app
Since the last time I updated this article the create-react-app world has significantly improved, so there are a few things I want to mention really quick just in case you had followed/read this article in the past and are curious what’s new!
Intended Audience
This tutorial is largely aimed at people who want to start exploring React and are at least comfortable with having nodejs/npm installed on their machines and people who have at least some background in Javascript and CSS. If you already know React, you can skip pretty much this entire tutorial (but if you’re curious about create-react-app, read the “Exploring Our First App” section!).
If you need to install nodejs/npm on your machine, please visit: https://nodejs.org/.
If you want to get started with Javascript, I recommend https://www.codecademy.com/learn/javascript
I’ll be covering some of the changes in ES2015 as we go along and explaining what they are/what they do/etc.
What Is Create-React-App
create-react-app is, quite simply, an answer to the common complaints of Javascript Fatigue or the sheer difficulty of getting started in a common React environment, which usually involves configuring a combination of things such as webpack, babel, and react. The complaints are best summed up in this tweet:
To their credit, the React team has done an amazing job and React is, in my mind, the simplest Javascript framework out there to jump into and get started with, but removing barriers to entry is something that every single developer out there should be striving for whenever possible.
Thus enters create-react-app. Now, getting started with React in a development environment that mirrors what you’d see working with React in a professional setting is very simple! And don’t worry, because the team has also helpfully included an “eject” command on create-react-app that pulls your new React application out of their base configuration and allows you to further tweak their base config into whatever toolset and modifications you’d prefer!
Installing Create-React-App
Assuming we already have node/npm installed, we can jump right into installing create-react-app! We’ll want to run the following command in our terminal:
Alternatively, if you’re big on using Yarn, you can use Yarn to install create-react-app globally instead!
We’ll verify that our install of create-react-app is working with:
Great! Let’s get started by making our favorite Hello World example!
Creating Our First React App
First, start off by moving into wherever you want to develop your application. In that directory, we’re going to create an app called “hello-world”:
The instructions at the end are really the important part. There are four default commands bundled into create-react-app: start, build, test, and eject. Also, notice that create-react-app now uses Yarn by default instead of just standard NPM. The descriptions are pretty self-explanatory, but let’s explore them in a little more detail:
This will start up a little development web server and give you a place to start working on your application. Running this will start up a development server at http://localhost:3000/ and give you a nice little starter template:
“Bundles the app into static files for production.” If you’re comfortable with webpack/brunch and the build process for production sites, then you probably know what this all means. However, if all of this is Greek to you, then we’ll explain a little more. Basically, this means it’s going to take all of the Javascript code that the browser can’t interpret without any help and turn it into a smaller (“minified”) version that the browser can read and understand. It shrinks the file down as much as it possibly can to reduce the download time (probably doesn’t matter when you’re sitting on a good internet connection, but the minute you drop to 3G or worse speeds you’ll be very thankful for this!) while keeping your application running!
“Starts the test runner.” create-react-app now ships with a bunch of tools all ready to go for you to start testing your app as you’re building it via Jest. The first time you run it you’ll probably see something like:
It’s always a great idea to run your tests as you go along, and now you get a really nice built-in way to do so (and trust me, trying to set all of this up on your own is a huge pain in the butt, so major props to the create-react-app team for this!)
“Removes this tool and copies build dependencies, configuration files and scripts into the app directory. If you do this, you can’t go back!” What this does is it pulls your application out of the context of the create-react-app framework and into a standard webpack build. This allows you to tweak the base create-react-app framework, either adding/removing dependencies, and perform more advanced manipulations of your app as necessary. You can think of this as a way to remove the scaffolding that create-react-app creates for you and look at the underlying project and dependency structure.
Exploring Our First App
Let’s start by looking at the first application that is created by create-react-app:
It helpfully generates a readme for your project ( README.md ) which is in Markdown format, as well as a favicon (the icon that shows up in your browser’s address bar and is used as the icon for bookmarks and whatnot). public/index.html is the main HTML file that includes your React code and application and provides a context for React to render to. Specifically, it includes a div that your react app will show up inside. Let’s take a look at the file:
Next, we have our package.json file. This is what stores the lists of dependencies for your application, as well as what describes your application (the name, the version number, etc). Similarly, we also have a yarn.lock file, which is basically a locked list of all dependencies of our app.
The node_modules/ directory is where all of the dependencies get built/stored. For the most part, you shouldn’t have to fiddle with this too much.
The important directory for us as developers is the src/ directory. This stores all of our modifiable code. We’ll explore the contents of that file really quickly, too.
index.js stores our main Render call from ReactDOM (more on that later). It imports our App.js component that we start off with and tells React where to render it (remember that div with an id of root?). index.css stores the base styling for our application.
App.js is a sample React component called “App” that we get for free when creating a new app. We’ll actually be deleting the entire contents of the file and starting over! App.css stores styling targeting that component specifically. Finally, logo.svg is just the React logo.
App.test.js is our first set of tests to run against our sample App component that we start off with.
Creating Our First Component
There are two primary ways to create components in React when you’re working with ES2015 code: through functions or through ES2015 classes. We’re actually going to start off by using functions to create our components and then work our way up to using classes, explaining the differences between the two/when to choose which/etc.
Either creation method requires that React actually be imported into our component, so let’s do that first. At the top (in src/App.js ), we’re going to add :
One line in and we’re already neck-deep in ES2015 code! This tells Javascript that we want to import the React library from the installed ‘react’ NPM module. That’s all! This gives us React support, JSX support, and everything we need from React to get started! Now, let’s write our hello world component!
Wait, What Is JSX?
If you already know what JSX is, you can skip this, but if not, here’s a quick summary:
JSX is a templating language that looks VERY similar to HTML. This allows you to write templates for your components in a way that’s very comfortable to developers already familiar with HTML, but there are a few extra things that it provides. First, you can embed any javascript inside of a JSX template by wrapping it in curly braces (these: <>). Second, some words are special and reserved, such as class, so there are JSX-specific properties/attributes/etc you need to use (such as className).
In addition, React components must only return a SINGLE JSX node at its root, so it’s very common to wrap up your components into a single div that might have multiple children underneath it.
Returning To Our Component
We have our component written, but if you look at the browser, everything is blank right now! We need to do one more thing in ES2015 to make sure other files can take advantage of any code written in this file: export.
At the bottom of our file, add the following line:
Now, when we save the file and our app reloads automatically, you’ll see our first component show up!
Embedding Stylesheets In Our Component
One trick that create-react-app does by default that is a nice thing to learn is embedded stylesheets for your components. Since we have a blank App.css file, let’s throw something in there to make our component more noticeable. Back at the top of our component (in src/App.js), below our import React line, add the following:
This imports the CSS file into our component. Next, open up src/App.css and add the following:
Save the file, and then head back to your browser window and you should see something like the following:
That’s a good place to start in our application, so we’ll hop over to index.js and very quickly figure out precisely how the component gets into the browser. Open up src/index.js :
Now we have our render call. Render is a function that takes two arguments:
In our case, we declare the component using JSX. Since our component name was imported as “App”, we can reference that app inside of a JSX template as if it were an HTML tag:
Note: All tags in JSX need to be closed, either inside of the tag such as above or like this:
Conclusion
Congratulations! You now have the start of a basic functional component in React with very little work! You have webpack and babel and everything else all figured out and installed for you but without a lot of the fuss or bother! This is a very nice, very clean way to get started with React development. In future tutorials, we’ll flesh out example a lot more by adding components via ES2015 classes, as well as adding concepts of state and props into our components. We’ll also discuss using the build and eject commands and what they mean!