Порефакторим...
В течении всего учебника я учил вас думать о данных, а потом в CWP и gDSFR взял и сделал из образно stateless (хоть он и был через class - состояния у него не было) компонента - statefull. Это было сделано для удобства объяснений.
Смотрите, если мы откатим наш <News />
на два урока назад (когда компонент просто получал props), то мы сможем в <App />
использовать gDSFR и там "рубить спам". Таким образом, мы бы опять решили задачу без изменения stateless компонента.
Было: компонент <News />
умел отображать данные. Стало: компонент <News />
умеет отображать данные и помечать спам.
Задача: обрабатывать данные в <App />
, вернуть <News />
к прежнему "тупому" образу жизни.
Подсказка: вы запросто можете сделать все что нужно в <App />
, так как мы только что отработали этот прием.
Подсказка: в <App />
новости лежат в state, а не в props.
Напоминаю, как выглядел <News />
:
src/components/News.js
import React from 'react'
import PropTypes from 'prop-types'
import { Article } from './Article'
class News extends React.Component {
renderNews = () => {
const { data } = this.props
let newsTemplate = null
if (data.length) {
newsTemplate = data.map(function(item) {
return <Article key={item.id} data={item} />
})
} else {
newsTemplate = <p>К сожалению новостей нет</p>
}
return newsTemplate
}
render() {
const { data } = this.props
return (
<div className="news">
{this.renderNews()}
{data.length ? (
<strong className={'news__count'}>
Всего новостей: {data.length}
</strong>
) : null}
</div>
)
}
}
News.propTypes = {
data: PropTypes.array.isRequired,
}
export { News }
Решение
Полный код компонента <App />
src/App.js
import React from 'react'
import { Add } from './components/Add'
import { News } from './components/News'
import './App.css'
class App extends React.Component {
state = {
news: null,
isLoading: false,
}
static getDerivedStateFromProps(props, state) {
let nextFilteredNews
// смотрим в state.news (ранее смотрели в props)
// и проверяем, чтобы не клоинировать null
// например, в момент первой отрисовки
if (Array.isArray(state.news)) {
nextFilteredNews = [...state.news]
nextFilteredNews.forEach((item, index) => {
if (item.bigText.toLowerCase().indexOf('pubg') !== -1) {
item.bigText = 'СПАМ'
}
})
return {
filteredNews: nextFilteredNews,
}
}
return null
}
componentDidMount() {
this.setState({ isLoading: true })
fetch('http://localhost:3000/data/newsData.json')
.then(response => {
return response.json()
})
.then(data => {
setTimeout(() => {
this.setState({ isLoading: false, news: data })
}, 1000) // изменил таймер на 1000, чтобы не ждать долго
})
}
handleAddNews = data => {
const nextNews = [data, ...this.state.news]
this.setState({ news: nextNews })
}
render() {
const { news, isLoading } = this.state
return (
<React.Fragment>
<Add onAddNews={this.handleAddNews} />
<h3>Новости</h3>
{isLoading && <p>Загружаю...</p>}
{Array.isArray(news) && <News data={news} />}
</React.Fragment>
)
}
}
export default App
Итого:
Last updated
Was this helpful?