This is my first small react app. I got a little experience in Vue.js before, but I wan't to learn the basics and best practices of react.js too. So, this is a small library app (containing link tipps with title, desc, topics) that shows all library items with the possibility to filter them by clicking on specific keywords. Pretty easy, but I want to know from you if I coded some bad practices or anti patterns or sth. like that.
main.js
import React from 'react'
import ReactDOM from 'react-dom'
import Library from './components/Library.jsx'
const libraryContainer = document.getElementById('library')
ReactDOM.render(<Library />, libraryContainer)
Library.jsx
import React from 'react'
import Filters from './Filters.jsx'
import LibraryItem from './LibraryItem.jsx'
import SmoothScroll from 'smooth-scroll'
const libraryContainer = document.getElementById('library')
const scroll = new SmoothScroll('a[href*="#"]', { offset: 100 })
export default class Library extends React.Component {
state = {
lib: [],
filteredLib: [],
topics: [],
filter: '',
}
filterLib = () => {
if (this.state.filter === '') return this.setState({ filteredLib: this.state.lib })
this.setState(
{
filteredLib: this.state.lib.filter(item => {
if (item.topics) return item.topics.includes(this.state.filter)
}),
},
() => scroll.animateScroll(libraryContainer),
)
}
handleFilters = topic => {
const topicsClone = JSON.parse(JSON.stringify(this.state.topics))
topicsClone.forEach(item => {
if (item.id === topic.id) {
item.active = !item.active
item.active ? null : (topic.name = '')
} else {
item.active = false
}
})
this.setState({ topics: topicsClone, filter: topic.name }, () => {
this.filterLib()
})
}
componentDidMount() {
let topicsArr = []
fetch('/api')
.then(res => res.json())
.then(data => {
this.setState({ lib: data.lib, filteredLib: data.lib })
data.topics.map((val, key) => {
topicsArr.push({ name: val, id: key, active: false })
})
this.setState({ topics: topicsArr })
})
.catch(err => console.log(err))
}
render() {
if (this.state.filteredLib.length > 0) {
return (
<div className="library-container">
<Filters topics={this.state.topics} handler={this.handleFilters} />
<div className="column column--content">
<ul className="cards">
{this.state.filteredLib.map(item => {
return <LibraryItem key={item._id} {...item} />
})}
</ul>
</div>
</div>
)
} else {
return <h4>Wir konnten leider nichts finden :(</h4>
}
}
}
Filters.jsx
import React from 'react'
export default function Filters(props) {
const handleClick = topic => {
props.handler(topic)
}
return (
<div className="column column--filters">
<h3 className="title">Filter</h3>
<ul className="filters">
{props.topics.map(topic => {
return (
<li key={topic.id} className={topic.active ? 'filters__item active' : 'filters__item'} onClick={() => handleClick(topic)}>
{topic.name}
</li>
)
})}
</ul>
</div>
)
}
LibraryItem.jsx
import React from 'react'
export default function LibraryItem(props) {
return (
<li className="cards__item card">
<a className="card__link" href={props.slug} />
<div className="card__header">
<p className="type">{props.type}</p>
<h3 className="card__title">{props.title}</h3>
</div>
<div className="card__content">
<p className="content">{props.teaser}</p>
</div>
</li>
)
}