В течении всего учебника я учил вас думать о данных, а потом в 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
Итого: