React Filter library
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
2
down vote
favorite
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>
)
beginner react.js jsx
add a comment |Â
up vote
2
down vote
favorite
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>
)
beginner react.js jsx
add a comment |Â
up vote
2
down vote
favorite
up vote
2
down vote
favorite
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>
)
beginner react.js jsx
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>
)
beginner react.js jsx
edited Jan 4 at 14:54
200_success
124k14143401
124k14143401
asked Jan 4 at 11:48
FNGR
1334
1334
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
1
down vote
accepted
Here is a review of the code. While some my comments / suggestions are related to JavaScript and not to react specifically, these do reflect common practices in React code.
I put a live version with the changes on codesandbox. I created a small API to have some data for the fetch
request. I also added a css file to test the active
behavior for the selected filter topics.
Library.jsx
componentDidMount()
:It is a common practice in react to use the
map
function to create a new array. Also, you can change the code so thatsetState
is only called once (for conciseness):componentDidMount()
fetch("https://demo5925186.mockable.io")
.then(res => res.json())
.then(data =>
const topics = data.topics.map((name, index) => (
name,
id: index,
active: false
));
this.setState(
lib: data.lib,
filteredLib: data.lib,
topics
);
)
.catch(err => console.log(err));render()
It can make your JSX easier to read if you extract properties from the
state
on the first line using object destructuring assignment:const filteredLib, topics = this.state;
It seems like you would always want to show the
Filters
component (the topic selection), even iffilteredLib.length
is equal to0
.render()
const filteredLib, topics = this.state;
return (
<div className="library-container">
<Filters topics=topics handleClick=this.handleFilters />
filteredLib.length === 0 ? (
<h4>Wir konnten leider nichts finden :(</h4>
) : (
<div className="column column--content">
<ul className="cards">
filteredLib.map(item => (
<LibraryItem key=item._id ...item />
))
</ul>
</div>
)
</div>
);handleFilters
I changed
state.filter
tostate.selectedTopic
and the input argument name fromtopic
tonewTopic
.Similarly to
componentDidMount
, thenewTopics
array can be created with map (you could convert the ternary to anif-else
statement). You can use the spread operator on each object to create a new object.It seems like
state.filter
would never be an empty string becausehandleFilters
always setsstate.filter
to whichever topic was selected. To fix this, you can compared the new selected topic to the existing one. If they are the same, the new selected topic should be set to an empty string.handleFilters = newTopic =>
const topics, selectedTopic = this.state;
const newTopics = topics.map(
topic =>
topic.id === newTopic.id
? ...topic, active: !topic.active
: ...topic, active: false
);
// If the new selected topic is same as the old one
// We will set state.selectedTopic to ""
const newSelectedTopic =
newTopic.name === selectedTopic ? "" : newTopic.name;
this.setState(
topics: newTopics,
selectedTopic: newSelectedTopic
,
() =>
this.filterLib();
);
;
Filters.jsx
It is common to define functional components with const
, and the parameters can be destructured in the function definition.
There is no need for the handleClick
method. You can change the name of props.handler
to props.handleClick
, and call it directly.
const Filters = ( topics, handleClick ) => (
<div className="column column--filters">
<h3 className="title">Filter</h3>
<ul className="filters">
topics.map(topic => (
<li
key=topic.id
className=
topic.active ? "filters__item active" : "filters__item"
onClick=() => handleClick(topic)
>
topic.name
</li>
))
</ul>
</div>
);
export default Filters;
1
Wow thank you Lev Izraelit! Your answer is awesome and helps me a lot to get better at react. I'll study every line and improve my code. Can't thank you enough.
â FNGR
Jan 13 at 8:33
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
Here is a review of the code. While some my comments / suggestions are related to JavaScript and not to react specifically, these do reflect common practices in React code.
I put a live version with the changes on codesandbox. I created a small API to have some data for the fetch
request. I also added a css file to test the active
behavior for the selected filter topics.
Library.jsx
componentDidMount()
:It is a common practice in react to use the
map
function to create a new array. Also, you can change the code so thatsetState
is only called once (for conciseness):componentDidMount()
fetch("https://demo5925186.mockable.io")
.then(res => res.json())
.then(data =>
const topics = data.topics.map((name, index) => (
name,
id: index,
active: false
));
this.setState(
lib: data.lib,
filteredLib: data.lib,
topics
);
)
.catch(err => console.log(err));render()
It can make your JSX easier to read if you extract properties from the
state
on the first line using object destructuring assignment:const filteredLib, topics = this.state;
It seems like you would always want to show the
Filters
component (the topic selection), even iffilteredLib.length
is equal to0
.render()
const filteredLib, topics = this.state;
return (
<div className="library-container">
<Filters topics=topics handleClick=this.handleFilters />
filteredLib.length === 0 ? (
<h4>Wir konnten leider nichts finden :(</h4>
) : (
<div className="column column--content">
<ul className="cards">
filteredLib.map(item => (
<LibraryItem key=item._id ...item />
))
</ul>
</div>
)
</div>
);handleFilters
I changed
state.filter
tostate.selectedTopic
and the input argument name fromtopic
tonewTopic
.Similarly to
componentDidMount
, thenewTopics
array can be created with map (you could convert the ternary to anif-else
statement). You can use the spread operator on each object to create a new object.It seems like
state.filter
would never be an empty string becausehandleFilters
always setsstate.filter
to whichever topic was selected. To fix this, you can compared the new selected topic to the existing one. If they are the same, the new selected topic should be set to an empty string.handleFilters = newTopic =>
const topics, selectedTopic = this.state;
const newTopics = topics.map(
topic =>
topic.id === newTopic.id
? ...topic, active: !topic.active
: ...topic, active: false
);
// If the new selected topic is same as the old one
// We will set state.selectedTopic to ""
const newSelectedTopic =
newTopic.name === selectedTopic ? "" : newTopic.name;
this.setState(
topics: newTopics,
selectedTopic: newSelectedTopic
,
() =>
this.filterLib();
);
;
Filters.jsx
It is common to define functional components with const
, and the parameters can be destructured in the function definition.
There is no need for the handleClick
method. You can change the name of props.handler
to props.handleClick
, and call it directly.
const Filters = ( topics, handleClick ) => (
<div className="column column--filters">
<h3 className="title">Filter</h3>
<ul className="filters">
topics.map(topic => (
<li
key=topic.id
className=
topic.active ? "filters__item active" : "filters__item"
onClick=() => handleClick(topic)
>
topic.name
</li>
))
</ul>
</div>
);
export default Filters;
1
Wow thank you Lev Izraelit! Your answer is awesome and helps me a lot to get better at react. I'll study every line and improve my code. Can't thank you enough.
â FNGR
Jan 13 at 8:33
add a comment |Â
up vote
1
down vote
accepted
Here is a review of the code. While some my comments / suggestions are related to JavaScript and not to react specifically, these do reflect common practices in React code.
I put a live version with the changes on codesandbox. I created a small API to have some data for the fetch
request. I also added a css file to test the active
behavior for the selected filter topics.
Library.jsx
componentDidMount()
:It is a common practice in react to use the
map
function to create a new array. Also, you can change the code so thatsetState
is only called once (for conciseness):componentDidMount()
fetch("https://demo5925186.mockable.io")
.then(res => res.json())
.then(data =>
const topics = data.topics.map((name, index) => (
name,
id: index,
active: false
));
this.setState(
lib: data.lib,
filteredLib: data.lib,
topics
);
)
.catch(err => console.log(err));render()
It can make your JSX easier to read if you extract properties from the
state
on the first line using object destructuring assignment:const filteredLib, topics = this.state;
It seems like you would always want to show the
Filters
component (the topic selection), even iffilteredLib.length
is equal to0
.render()
const filteredLib, topics = this.state;
return (
<div className="library-container">
<Filters topics=topics handleClick=this.handleFilters />
filteredLib.length === 0 ? (
<h4>Wir konnten leider nichts finden :(</h4>
) : (
<div className="column column--content">
<ul className="cards">
filteredLib.map(item => (
<LibraryItem key=item._id ...item />
))
</ul>
</div>
)
</div>
);handleFilters
I changed
state.filter
tostate.selectedTopic
and the input argument name fromtopic
tonewTopic
.Similarly to
componentDidMount
, thenewTopics
array can be created with map (you could convert the ternary to anif-else
statement). You can use the spread operator on each object to create a new object.It seems like
state.filter
would never be an empty string becausehandleFilters
always setsstate.filter
to whichever topic was selected. To fix this, you can compared the new selected topic to the existing one. If they are the same, the new selected topic should be set to an empty string.handleFilters = newTopic =>
const topics, selectedTopic = this.state;
const newTopics = topics.map(
topic =>
topic.id === newTopic.id
? ...topic, active: !topic.active
: ...topic, active: false
);
// If the new selected topic is same as the old one
// We will set state.selectedTopic to ""
const newSelectedTopic =
newTopic.name === selectedTopic ? "" : newTopic.name;
this.setState(
topics: newTopics,
selectedTopic: newSelectedTopic
,
() =>
this.filterLib();
);
;
Filters.jsx
It is common to define functional components with const
, and the parameters can be destructured in the function definition.
There is no need for the handleClick
method. You can change the name of props.handler
to props.handleClick
, and call it directly.
const Filters = ( topics, handleClick ) => (
<div className="column column--filters">
<h3 className="title">Filter</h3>
<ul className="filters">
topics.map(topic => (
<li
key=topic.id
className=
topic.active ? "filters__item active" : "filters__item"
onClick=() => handleClick(topic)
>
topic.name
</li>
))
</ul>
</div>
);
export default Filters;
1
Wow thank you Lev Izraelit! Your answer is awesome and helps me a lot to get better at react. I'll study every line and improve my code. Can't thank you enough.
â FNGR
Jan 13 at 8:33
add a comment |Â
up vote
1
down vote
accepted
up vote
1
down vote
accepted
Here is a review of the code. While some my comments / suggestions are related to JavaScript and not to react specifically, these do reflect common practices in React code.
I put a live version with the changes on codesandbox. I created a small API to have some data for the fetch
request. I also added a css file to test the active
behavior for the selected filter topics.
Library.jsx
componentDidMount()
:It is a common practice in react to use the
map
function to create a new array. Also, you can change the code so thatsetState
is only called once (for conciseness):componentDidMount()
fetch("https://demo5925186.mockable.io")
.then(res => res.json())
.then(data =>
const topics = data.topics.map((name, index) => (
name,
id: index,
active: false
));
this.setState(
lib: data.lib,
filteredLib: data.lib,
topics
);
)
.catch(err => console.log(err));render()
It can make your JSX easier to read if you extract properties from the
state
on the first line using object destructuring assignment:const filteredLib, topics = this.state;
It seems like you would always want to show the
Filters
component (the topic selection), even iffilteredLib.length
is equal to0
.render()
const filteredLib, topics = this.state;
return (
<div className="library-container">
<Filters topics=topics handleClick=this.handleFilters />
filteredLib.length === 0 ? (
<h4>Wir konnten leider nichts finden :(</h4>
) : (
<div className="column column--content">
<ul className="cards">
filteredLib.map(item => (
<LibraryItem key=item._id ...item />
))
</ul>
</div>
)
</div>
);handleFilters
I changed
state.filter
tostate.selectedTopic
and the input argument name fromtopic
tonewTopic
.Similarly to
componentDidMount
, thenewTopics
array can be created with map (you could convert the ternary to anif-else
statement). You can use the spread operator on each object to create a new object.It seems like
state.filter
would never be an empty string becausehandleFilters
always setsstate.filter
to whichever topic was selected. To fix this, you can compared the new selected topic to the existing one. If they are the same, the new selected topic should be set to an empty string.handleFilters = newTopic =>
const topics, selectedTopic = this.state;
const newTopics = topics.map(
topic =>
topic.id === newTopic.id
? ...topic, active: !topic.active
: ...topic, active: false
);
// If the new selected topic is same as the old one
// We will set state.selectedTopic to ""
const newSelectedTopic =
newTopic.name === selectedTopic ? "" : newTopic.name;
this.setState(
topics: newTopics,
selectedTopic: newSelectedTopic
,
() =>
this.filterLib();
);
;
Filters.jsx
It is common to define functional components with const
, and the parameters can be destructured in the function definition.
There is no need for the handleClick
method. You can change the name of props.handler
to props.handleClick
, and call it directly.
const Filters = ( topics, handleClick ) => (
<div className="column column--filters">
<h3 className="title">Filter</h3>
<ul className="filters">
topics.map(topic => (
<li
key=topic.id
className=
topic.active ? "filters__item active" : "filters__item"
onClick=() => handleClick(topic)
>
topic.name
</li>
))
</ul>
</div>
);
export default Filters;
Here is a review of the code. While some my comments / suggestions are related to JavaScript and not to react specifically, these do reflect common practices in React code.
I put a live version with the changes on codesandbox. I created a small API to have some data for the fetch
request. I also added a css file to test the active
behavior for the selected filter topics.
Library.jsx
componentDidMount()
:It is a common practice in react to use the
map
function to create a new array. Also, you can change the code so thatsetState
is only called once (for conciseness):componentDidMount()
fetch("https://demo5925186.mockable.io")
.then(res => res.json())
.then(data =>
const topics = data.topics.map((name, index) => (
name,
id: index,
active: false
));
this.setState(
lib: data.lib,
filteredLib: data.lib,
topics
);
)
.catch(err => console.log(err));render()
It can make your JSX easier to read if you extract properties from the
state
on the first line using object destructuring assignment:const filteredLib, topics = this.state;
It seems like you would always want to show the
Filters
component (the topic selection), even iffilteredLib.length
is equal to0
.render()
const filteredLib, topics = this.state;
return (
<div className="library-container">
<Filters topics=topics handleClick=this.handleFilters />
filteredLib.length === 0 ? (
<h4>Wir konnten leider nichts finden :(</h4>
) : (
<div className="column column--content">
<ul className="cards">
filteredLib.map(item => (
<LibraryItem key=item._id ...item />
))
</ul>
</div>
)
</div>
);handleFilters
I changed
state.filter
tostate.selectedTopic
and the input argument name fromtopic
tonewTopic
.Similarly to
componentDidMount
, thenewTopics
array can be created with map (you could convert the ternary to anif-else
statement). You can use the spread operator on each object to create a new object.It seems like
state.filter
would never be an empty string becausehandleFilters
always setsstate.filter
to whichever topic was selected. To fix this, you can compared the new selected topic to the existing one. If they are the same, the new selected topic should be set to an empty string.handleFilters = newTopic =>
const topics, selectedTopic = this.state;
const newTopics = topics.map(
topic =>
topic.id === newTopic.id
? ...topic, active: !topic.active
: ...topic, active: false
);
// If the new selected topic is same as the old one
// We will set state.selectedTopic to ""
const newSelectedTopic =
newTopic.name === selectedTopic ? "" : newTopic.name;
this.setState(
topics: newTopics,
selectedTopic: newSelectedTopic
,
() =>
this.filterLib();
);
;
Filters.jsx
It is common to define functional components with const
, and the parameters can be destructured in the function definition.
There is no need for the handleClick
method. You can change the name of props.handler
to props.handleClick
, and call it directly.
const Filters = ( topics, handleClick ) => (
<div className="column column--filters">
<h3 className="title">Filter</h3>
<ul className="filters">
topics.map(topic => (
<li
key=topic.id
className=
topic.active ? "filters__item active" : "filters__item"
onClick=() => handleClick(topic)
>
topic.name
</li>
))
</ul>
</div>
);
export default Filters;
edited Jan 12 at 3:11
Jamalâ¦
30.1k11114225
30.1k11114225
answered Jan 12 at 0:17
Lev Izraelit
262
262
1
Wow thank you Lev Izraelit! Your answer is awesome and helps me a lot to get better at react. I'll study every line and improve my code. Can't thank you enough.
â FNGR
Jan 13 at 8:33
add a comment |Â
1
Wow thank you Lev Izraelit! Your answer is awesome and helps me a lot to get better at react. I'll study every line and improve my code. Can't thank you enough.
â FNGR
Jan 13 at 8:33
1
1
Wow thank you Lev Izraelit! Your answer is awesome and helps me a lot to get better at react. I'll study every line and improve my code. Can't thank you enough.
â FNGR
Jan 13 at 8:33
Wow thank you Lev Izraelit! Your answer is awesome and helps me a lot to get better at react. I'll study every line and improve my code. Can't thank you enough.
â FNGR
Jan 13 at 8:33
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184274%2freact-filter-library%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password