В сегодняшней части перевода учебного курса по React мы завершим работу над Todo-приложением и поговорим о том, как, пользуясь внутренними механизмами компонентов и стандартными возможностями JavaScript, загружать данные из внешних источников.
> Часть 1: обзор курса, причины популярности React, ReactDOM и JSX
> Часть 2: функциональные компоненты
> Часть 3: файлы компонентов, структура проектов
> Часть 4: родительские и дочерние компоненты
> Часть 5: начало работы над TODO-приложением, основы стилизации
> Часть 6: о некоторых особенностях курса, JSX и JavaScript
> Часть 7: встроенные стили
> Часть 8: продолжение работы над TODO-приложением, знакомство со свойствами компонентов
> Часть 9: свойства компонентов
> Часть 10: практикум по работе со свойствами компонентов и стилизации
> Часть 11: динамическое формирование разметки и метод массивов map
> Часть 12: практикум, третий этап работы над TODO-приложением
> Часть 13: компоненты, основанные на классах
> Часть 14: практикум по компонентам, основанным на классах, состояние компонентов
> Часть 15: практикумы по работе с состоянием компонентов
> Часть 16: четвёртый этап работы над TODO-приложением, обработка событий
> Часть 17: пятый этап работы над TODO-приложением, модификация состояния компонентов
> Часть 18: шестой этап работы над TODO-приложением
> Часть 19: методы жизненного цикла компонентов
> Часть 20: первое занятие по условному рендерингу
> Часть 21: второе занятие и практикум по условному рендерингу
> Часть 22: седьмой этап работы над TODO-приложением, загрузка данных из внешних источников
TodoItem
выглядит так:import React from "react"
function TodoItem(props) {
return (
<div className="todo-item">
<input
type="checkbox"
checked={props.item.completed}
onChange={() => props.handleChange(props.item.id)}
/>
<p>{props.item.text}</p>
</div>
)
}
export default TodoItem
completedStyle
в коде функционального компонента TodoItem
. Тут мы настроим свойства текста fontStyle
, color
и textDecoration
. После этого, пользуясь методикой условного рендеринга, назначим этот стиль элементу <p>
в том случае, если выводимое им дело отмечено как завершённое. Определять это будем, ориентируясь на переданное экземпляру компонента свойство, которое доступно в нём как props.item.completed
. import React from "react"
function TodoItem(props) {
const completedStyle = {
fontStyle: "italic",
color: "#cdcdcd",
textDecoration: "line-through"
}
return (
<div className="todo-item">
<input
type="checkbox"
checked={props.item.completed}
onChange={() => props.handleChange(props.item.id)}
/>
<p style={props.item.completed ? completedStyle: null}>{props.item.text}</p>
</div>
)
}
export default TodoItem
componentDidMount()
. Попытайтесь вспомнить о том, как именно он работает. Этот метод позволяет вмешиваться в работу компонента, выполняя некий код сразу после того, как компонент был добавлен в дерево DOM. Когда мы говорили о методах жизненного цикла компонентов, я упоминал о том, что метод componentDidMount()
чаще всего используется для загрузки данных из неких внешних источников. Эти данные используются компонентом для реализации его предназначения.App.js
которого содержит следующий код:import React, {Component} from "react"
class App extends Component {
constructor() {
super()
this.state = {}
}
render() {
return (
<div>
Code goes here
</div>
)
}
}
export default App
App
, основанного на классе, метод componentDidMount()
и проверим работоспособность полученной конструкции, выведя из этого метода что-нибудь в консоль.import React, {Component} from "react"
class App extends Component {
constructor() {
super()
this.state = {}
}
componentDidMount() {
console.log("Hi!")
}
render() {
return (
<div>
Code goes here
</div>
)
}
}
export default App
Hi!
доказывает работоспособность кода, поэтому мы можем продолжать работу. Как уже было сказано, в этом методе обычно загружают данные, необходимые для работы компонента.componentDidMount()
мы собираемся воспользоваться функцией fetch()
, передав ей адрес для загрузки данных, преобразовать эти данные к нужному нам виду, и, для того, чтобы проверить правильность работы системы, вывести эти данные в консоль. Преобразуем код метода к следующему виду:componentDidMount() {
fetch("https://swapi.co/api/people/1")
.then(response => response.json())
.then(data => console.log(data))
}
character
, представленное пустым объектом:this.state = {
character: {}
}
character
пустым объектом.componentDidMount()
, где мы получаем данные, мы запишем их в состояние, воспользовавшись методом setState()
. При этом в данном случае то, что хранилось в состоянии до этого, нас не интересует, поэтому мы можем просто передать этому методу объект, содержащий новое представление состояния. В итоге мы приходим к такому коду метода componentDidMount()
:componentDidMount() {
fetch("https://swapi.co/api/people/1")
.then(response => response.json())
.then(data => {
this.setState({
character: data
})
})
}
render()
что-нибудь, что должно присутствовать в состоянии после записи в него загруженных данных. Теперь код файла App.js
будет выглядеть так:import React, {Component} from "react"
class App extends Component {
constructor() {
super()
this.state = {
character: {}
}
}
componentDidMount() {
fetch("https://swapi.co/api/people/1")
.then(response => response.json())
.then(data => {
this.setState({
character: data
})
})
}
render() {
return (
<div>
{this.state.character.name}
</div>
)
}
}
export default App
Luke Skywalker
демонстрирует правильную работу механизмов загрузки данных.loading...
. Делая это, мы сможем оценить возможности, которые даёт нам хранение данных в состоянии приложения.loading
и инициализируем его значением false
. После этого, сразу перед тем, как выполнять загрузку данных с использованием fetch()
, запишем в это свойство true
.render()
, опираясь на свойство состояния loading
, настроим текст, выводимый на страницу. Вот как будет выглядеть код App.js
после этих преобразований.import React, {Component} from "react"
class App extends Component {
constructor() {
super()
this.state = {
loading: false,
character: {}
}
}
componentDidMount() {
this.setState({loading: true})
fetch("https://swapi.co/api/people/1")
.then(response => response.json())
.then(data => {
this.setState({
character: data
})
})
}
render() {
const text = this.state.loading ? "loading..." : this.state.character.name
return (
<div>
<p>{text}</p>
</div>
)
}
}
export default App
loading...
должна выводиться на ней только во время загрузки данных из внешнего источника, но она, судя по всему, выводится теперь на странице постоянно. Попытайтесь, прежде чем читать дальше, найти и исправить ошибки в коде.loading
в true
, а после завершения загрузки не записали в loading
false
. В результате на странице всегда выводится текст loading...
. Исправить эту ошибку несложно. Достаточно, там же, где мы записываем в состояние загруженные данные, установить loading
в значение false
. В результате код App.js
приобретёт следующий вид:import React, {Component} from "react"
class App extends Component {
constructor() {
super()
this.state = {
loading: false,
character: {}
}
}
componentDidMount() {
this.setState({loading: true})
fetch("https://swapi.co/api/people/1")
.then(response => response.json())
.then(data => {
this.setState({
loading: false,
character: data
})
})
}
render() {
const text = this.state.loading ? "loading..." : this.state.character.name
return (
<div>
<p>{text}</p>
</div>
)
}
}
export default App
loading...
, а после этого на страницу выводится имя персонажа.componentDidMount()
и стандартным API Fetch, загружать данные из внешних источников, обрабатывать их и выводить на страницы. Кроме того, здесь мы поговорили о реализации механизма оповещения пользователя о выполнении приложением операций, которые могут занимать достаточно много времени. В следующий раз поговорим о формах.К сожалению, не доступен сервер mySQL