The backend calls to increment likes depicted by handleLike() and handleLike() functions successfully return the response of containing the number that's been incremented/decremented.
Unfortunately, this is the only way I can see photos.likes incremented/decrement in real time.
My question is: How do I make it so that I able to only increment/decrement the likes amount by 1 for the specific image's UserID that's being clicked on instead of ALL of them. Also, is there a way to avoid using frontend logic to accomplish this since the increment/decrement is happening on the server side?
I've hit a wall on this and not sure how to overcome it.
const [currentUserClicks, setCurrentUserClicks] = useState(1);
const [onChangeLikes, setonChangeLikes] = useState(null);
const handleLikesBasedOnUserId = (likedPhotoUserId) => {
if(currentUserClicks > 1) {
setCurrentUserClicks(currentUserClicks - 1);
handleDisLike(likedPhotoUserId); // sends data to server to decrement DB column
setonChangeLikes(false);
} else {
setCurrentUserClicks(currentUserClicks + 1);
handleLike(likedPhotoUserId); // sends data to server to increment DB column
setonChangeLikes(true);
}
};
return(
{
data.map((photos, index) => {
return <>
<div key={index}>
<img src={photos.url} alt="Photo" className="gallery-img" onClick={() => handleLikesBasedOnUserId(photos.UserID)}/>
<h5 className="likes">Likes: {!onChangeLikes ? photos.likes - 1: photos.likes + 1}</h5>
</div>
</>
})
}
);
In these cases you need to move the state locally to the mapped elements:
const { useState, useEffect } = React;
const App = () => data.map((pic) => <Pic key={pic.id} data={pic} />);
const Pic = ({ data }) => {
const [likes, setLikes] = useState(data.likes);
const handleClick = (type) => {
if (type === 'increment') {
if (likes - data.likes <= 0) {
// handleLike(id); // sends data to server to increment DB column
setLikes((l) => l + 1);
} else {
// handleDisLike(id); // sends data to server to decrement DB column
setLikes((l) => l - 1);
}
}
if (type === 'decrement') {
if (likes - data.likes >= 0) {
// handleDisLike(id); // sends data to server to decrement DB column
setLikes((l) => l - 1);
} else {
// handleLike(id); // sends data to server to increment DB column
setLikes((l) => l + 1);
}
}
};
return (
<div>
<img src={data.url} alt="Photo" className="gallery-img" />
<div className="container">
<h5 onClick={() => handleClick('decrement')}>-</h5>
<h5 className="likes">
Likes:
{likes}
</h5>
<h5 onClick={() => handleClick('increment')}>+</h5>
</div>
</div>
);
};
const data = [
{
url: 'https://upload.wikimedia.org/wikipedia/commons/a/a6/Pink_lady_and_cross_section.jpg',
likes: 10,
id: 'apple1',
},
{
url: 'https://upload.wikimedia.org/wikipedia/commons/2/22/Malus_domestica_a1.jpg',
likes: 25,
id: 'apple2',
},
];
const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(<App/>)
.gallery-img {
width: 100px;
}
.container {
display: flex;
}
h5 {
cursor: pointer;
margin: 10px;
}
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
I was not sure what you were trying to do since you did not have any like/dislike button, so I was not sure of your logic:
(first click --> like | second click --> reset | third click ?)
So I added two like/dislike clickables and tweaked a bit the logic to permit only one like/dislike vote, and reset if trying to increase/decrease further, as it works here on StackOverflow.
Consider that you should handle this logic serverside by the way, and you should make a call on component mount to check if the user has already voted or not, in a real world scenario, or it's enough a refresh to be able to vote multiple times.
Related
i use usestate to create saveImages and setSaveImages, this initial as array, i want to each time i call the function, the content is different, so each time must to push to the array that info, but instead of do push, only replace the 1 position of array, doesnt add new position with different info. I don't know if I explain myself
const galery = useSelector((state) => state.search);
const dispatch = useDispatch();
const [saveImages, setSaveImages] = useState([]);
function savePhoto(e) {
e.preventDefault();
const { target } = e;
const content = target.photo.src;
setSaveImages(content)
console.log(content)
localStorage.setItem("img", saveImages);
dispatch(actionAddFavorite(content));
}
return(
<section className="w-full gap-0 sm:columns-2 md:columns-3 xl:columns-4 2xl:columns-5 3xl:columns-6">
{galery.map((item, index) => {
return (
<form onSubmit={savePhoto} key={index} className="relative">
<button className="bg-gray absolute left-5 top-3 shadow-md">
Guardar
</button>
<img
name="photo"
className="object-cover p-2"
src={item.urls.regular}
alt={item.alt_description}
/>
</form>
);
})}
</section>
)
You set your saveImages to contain "content", but what you want is to add "content" to existing saveImages array. Here is how you can do this:
setSaveImages(oldImages => {
return [...oldImages, content];
});
And here you can learn everything you need to know about state in react
What is the problem?
I have a functional component that should render a list of player stats based on what team the user selects. The functionality of getting the data works and when I console log the state array using a useEffect I get an array with data inside it, but when I try to render the objects in html so you can see them on the screen sometimes they flicker on and then disappear, sometimes nothing happens at all.
What I've tried
I've tried using both a state array and just an ordinary variable array to see if that makes any difference. I've tried using .forEach and just a for loop to see if that would work. I've messed around with how I store the data and just trying to use a simple array instead of an object nothing so far has managed to get it rendered. As a note it is clear that the component does render as the div (className = Player-Stats) that contains the .map function is visible when inspected.
Thanks for any help and suggestions, I've spent days on this one functionality because the NHL api stores it's data super weirdly and you need to do all kinds of things to get the data you want. I didn't want to spam this question with tons of my code so if you need anything else like the parent components please ask and I can provide them.
Code Snippets
Landing Page
import { useState } from 'react';
import '../CSS/LandingPage.css';
import Instruction from './Instruction';
import LeagueLeaders from './LeagueLeaders';
import NavBar from './NavBar';
import TeamSelector from './TeamSelector';
import TeamStandings from './TeamStandings';
function LandingPage() {
const [teamSelected, setTeamSelected] = useState(false);
const [listOfTeams, setListOfTeams] = useState([]);
return (
<div className = 'Landing-Page-Container'>
<NavBar/>
<div className = 'Stats-Standings-Container'>
<div className = 'Team-Select-Container'>
<TeamSelector toggleStats = {setTeamSelected} setListTeams = {setListOfTeams}/>
</div>
<div className = 'Stats-Container'>
<LeagueLeaders showStats = {teamSelected} getListTeams = {listOfTeams} />
</div>
<div className = 'Standings-Container'>
<TeamStandings/>
</div>
</div>
</div>
);
}
export default LandingPage;
LeagueLeaders code
import { useState } from 'react';
import {FaChevronLeft, FaChevronRight} from 'react-icons/fa';
import '../CSS/LeagueLeaders.css';
import Instruction from './Instruction';
import LeaderStats from './LeaderStats.js';
function LeagueLeaders({showStats, getListTeams}){
var title = ['Skaters', 'Goalies', 'Defencemen'];
var [titleNo, setTitleNo] = useState(0);
var goalieOptions = ['GAA', 'SV%', 'SHUTOUTS'];
var nonGoalieOptions = ['POINTS', 'GOALS', 'ASSISTS'];
function selectPosition(task){
if(task === '+' && titleNo <2){
setTitleNo(titleNo+1);
}else if (task === '+' && titleNo == 2){
setTitleNo(0);
}else if(task === '-' && titleNo >0){
setTitleNo(titleNo-1);
}else{
setTitleNo(2);
}
}
return(
<div className = 'Leaders-Container'>
<div className = 'Leaders-Title'>
<FaChevronLeft className = 'toggleArrow' size = {24} color = 'white' onClick={() => selectPosition('-')}/>
<h1>{title[titleNo]}</h1>
<FaChevronRight className = 'toggleArrow' size = {24} color = 'white' onClick={() => selectPosition('+')}/>
</div>
<div className = 'Leaders-Selection-Container'>
<div className = 'Stat-Select-1'>
<p>{titleNo == 1 ? goalieOptions[0]: nonGoalieOptions[0]}</p>
</div>
<div className = 'Stat-Select-2'>
<p>{titleNo == 1 ? goalieOptions[1]: nonGoalieOptions[1]}</p>
</div>
<div className = 'Stat-Select-3'>
<p>{titleNo == 1 ? goalieOptions[2]: nonGoalieOptions[2]}</p>
</div>
</div>
<div className = 'Leaders-Stats-Container'>
{showStats ? <LeaderStats playerPos = {titleNo} teams = {getListTeams}/> : <Instruction/>}
</div>
</div>
);
}
export default LeagueLeaders;
TeamSelector component code
import '../CSS/TeamSelector.css';
import { useEffect, useState } from "react";
import teamDetail from "../Assets/teamDetail";
function TeamSelector( {toggleStats, setListTeams}) {
const [listOfTeams, setListOfTeams] = useState([]);
const [listOfURL, setListOfURL] = useState([]);
const [selectedTeams, setSelectedTeams] = useState([]);
useEffect(()=>{
console.log(selectedTeams);
setListTeams(selectedTeams);
}, [selectedTeams])
function handleClick(e){
const selectedTeamsCopy = [...selectedTeams];
if(selectedTeams.includes(e.currentTarget.id)){
if(selectedTeams.length <= 1){
toggleStats(false);
selectedTeamsCopy.splice(selectedTeamsCopy.indexOf(e.currentTarget.id, 1), 1);
setSelectedTeams(selectedTeamsCopy);
}else{
selectedTeamsCopy.splice(selectedTeamsCopy.indexOf(e.currentTarget.id, 1), 1);
setSelectedTeams(selectedTeamsCopy);
}
}else {
if(selectedTeams.length === 0){
toggleStats(true);
selectedTeamsCopy.push(e.currentTarget.id);
setSelectedTeams(selectedTeamsCopy);
}else{
selectedTeamsCopy.push(e.currentTarget.id);
setSelectedTeams(selectedTeamsCopy);
}
}
if(e.target.style.opacity === '1'){
e.target.style.opacity = '25%';
}else {
e.target.style.opacity = '100%';
}
}
return (
<div className = 'Team-Logo-Container'>
{teamDetail.map((Teams)=>(
<div>
<img onClick={(e) => handleClick(e)} key = {Teams.ID} id = {Teams.ID} alt = {Teams.Name +' Logo'} src = {Teams.URL} className = 'logo'/>
</div>
))}
</div>
);
}
export default TeamSelector;
Array of objects layout
[{ ID: "8480003", Name: "Jesper Boqvist", Points: "1", β¦ }, { ID: "8475193", Name: "Tomas Tatar", Points: "10", β¦ }, etc. etc.]
Rendering the array
return(
<div className = 'Player-Stats'>
{triggerStats ? listOfStats.map((d)=>{
return <p className = 'Stats' key={d.ID}>{d.ID}</p>}
) : <p className = 'Stats'> Sorry theres no available data</p>}
</div>
)
LeaderStats component script (Where the rendering issue is)
import { useEffect, useState, useRef } from "react";
import '../CSS/LeaderStats.css';
function LeaderStats({playerPos, teams}){
const isInitialMount = useRef(true);
const [listOfStats, setListOfStats] = useState([]);
const [triggerStats, setTriggerStats] = useState(false);
//If it's not the first render and the listOfStats state has changed it will render the stats of the players
useEffect(()=>{
if(!isInitialMount.current){
console.log(listOfStats);
setTriggerStats(true);
}
}, [listOfStats])
//When teams prop changes, run the function to get player data from API
useEffect(()=>{
if (isInitialMount.current) {
isInitialMount.current = false;
}else{
if(teams.length !== 0){
getPlayerIDs(teams);
}else{
setTriggerStats(false);
}
}
},[teams])
//This function runs all the axios calls and gathers data from multiple endpoints and saves it to an array
function getPlayerIDs(teamID){
const axios = require('axios');
var playerList=[];
var tempObj;
teamID.forEach(d =>
axios.get(`https://statsapi.web.nhl.com/api/v1/teams/${parseInt(d)}/roster`).then(res => {
//If user has selected the forward position filter roster by that player position and get the stats and save to temp array.
if(playerPos === 0){
res.data.roster.filter(obj => obj.position.type === 'Forward').map(e=>
axios.get(`https://statsapi.web.nhl.com/api/v1/people/${e.person.id}/stats?stats=statsSingleSeason&season=20212022`).then(res =>{
if(typeof res.data.stats[0].splits[0] !== 'undefined'){
if(playerPos !== 1 ){
tempObj = { ID: `${e.person.id}`, Name: `${e.person.fullName}` ,Points: `${res.data.stats[0].splits[0].stat.points}`, Goals: `${res.data.stats[0].splits[0].stat.goals}`, Assists: `${res.data.stats[0].splits[0].stat.assists}`};
playerList.push(tempObj);
}
}
})
);
}
//If user has selected the goalie position filter roster by that player position and get the stats and save to temp array.
else if(playerPos === 1){
res.data.roster.filter(obj => obj.position.type === 'Goalie').map(e=>
axios.get(`https://statsapi.web.nhl.com/api/v1/people/${e.person.id}/stats?stats=statsSingleSeason&season=20212022`).then(res =>{
if(typeof res.data.stats[0].splits[0] !== 'undefined'){
if(playerPos !== 1 ){
tempObj = { ID: `${e.person.id}`, Name: `${e.person.fullName}`, GAA: `${res.data.stats[0].splits[0].stat.goalAgainstAverage}`, SavePercentage: `${res.data.stats[0].splits[0].stat.savePercentage}`, Shutouts: `${res.data.stats[0].splits[0].stat.shutouts}`};
playerList.push(tempObj);
}
}
})
);
}
//If user has selected the defense position filter roster by that player position and get the stats and save to temp array.
else if(playerPos === 2){
res.data.roster.filter(obj => obj.position.type === 'Defenseman').map(e=>
axios.get(`https://statsapi.web.nhl.com/api/v1/people/${e.person.id}/stats?stats=statsSingleSeason&season=20212022`).then(res =>{
if(typeof res.data.stats[0].splits[0] !== 'undefined'){
if(playerPos !== 1 ){
tempObj = { ID: `${e.person.id}`, Name: `${e.person.fullName}` ,Points: `${res.data.stats[0].splits[0].stat.points}`, Goals: `${res.data.stats[0].splits[0].stat.goals}`, Assists: `${res.data.stats[0].splits[0].stat.assists}`};
playerList.push(tempObj);
}
}
})
);
}
})
);
//Set the state to the temp array that will be used to render the stats
setListOfStats(playerList);
}
return(
<div className = 'Player-Stats'>
{triggerStats ? listOfStats.map((d)=>{
return <p className = 'Stats' key={d.ID}>{d.ID}</p>}
) : <p className = 'Stats'> Sorry theres no available data</p>}
</div>
)
}
export default LeaderStats;
I have managed to figure out the issue so I'll post it here for those of you who in the future might find yourself in the same position as me without being able to find an answer. Turns out the way I was setting setListOfStats(playerList); made the state change without me realising it and by the time it got to rendering the .map there was nothing actually there as console.log takes a snapshot of the state at the time of the console.log. The solution (which I had experimented with before a few times but couldn't get working) was to remove the temprorary array of playerList completely and change the following code playerList.push(tempObj); to setListOfStats(listOfStats => [...listOfStats, tempObj]) thise line of code essentially sets the list of stats as I did before but it captures the previous state as well. This comes up with another issue of when you want to remove some data from the list but that's not related to this question. Hopefully someone can make use of this answer in the future.
For a bit of background information: this app is supposed to load a map api and create a workout form linked to a location selected on the map by clicking. Once the map is clicked, a form is loaded to fill out info about that workout and then it's saved to the #workout variable.
Problem: I'm trying to save the #workout variable to local storage to then load all the workouts from storage whenever the page is reloaded.
I'm trying to run the _getLocalStorage() function in the constructor to load items from the local storage when the page loads, but I keep getting this TypeError code:
script.js:239 Uncaught TypeError: this[#workout].forEach is not a function
at App._getLocalStorage (script.js:239)
at new App (script.js:21)
Code:
class App {
#map;
#mapEvent;
#workout = [];
constructor() {
this._getPosition();
this._getLocalStorage();
form.addEventListener('submit', this._newWorkout.bind(this));
inputType.addEventListener('change', this._toggleElevationField);
containerWorkouts.addEventListener('click', this._panToWorkout.bind(this));
}
_panToWorkout(e) {
// find the workout
const workoutEl = e.target.closest('.workout');
if (!workoutEl) return;
const workout = this.#workout.find(
work => work.id === workoutEl.dataset.id
);
// pan to workout object with that id number
this.#map.setView(workout.coords, 13, {
animate: true,
pan: {
duration: 1,
easeLinearity: 0.8,
},
});
}
_getPosition() {
// -> check if this nagivator.geolocation object exits, then loads the map.
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
this._loadMap.bind(this),
function () {
alert("Can't get your position");
}
);
}
}
_loadMap(position) {
const { latitude, longitude } = position.coords;
// -> creating a coordinate variable because the below L.map().setView function expects an array for the coordinates.
// -> adding the map loading script from the imported library after getting coordinates
this.#map = L.map('map').setView([latitude, longitude], 13);
L.tileLayer('https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png').addTo(
this.#map
);
// -> SETUP MAP CLICK LISTENER && OPEN FORM
this.#map.on('click', this._showForm.bind(this));
}
_showForm(event) {
this.#mapEvent = event;
form.classList.remove('hidden');
inputDistance.focus();
}
_hideForm() {
// -> Clear form values when submit
inputDistance.value =
inputCadence.value =
inputDuration.value =
inputElevation.value =
'';
// -> removes the form from view to disable the slide transition while it's being removed.
form.style.display = 'none';
form.classList.add('hidden');
setTimeout(() => (form.style.display = 'grid'), 1000);
}
_toggleElevationField() {
inputElevation.closest('.form__row').classList.toggle('form__row--hidden');
inputCadence.closest('.form__row').classList.toggle('form__row--hidden');
}
_newWorkout(e) {
// -> prevent default submit function which is to refresh the page
e.preventDefault();
const validInput = (...inputs) =>
inputs.every(entry => Number.isFinite(entry));
const allPositive = (...inputs) => inputs.every(inp => inp > 0);
// -> Get data from form
const type = inputType.value;
const distance = +inputDistance.value;
const duration = +inputDuration.value;
const { lat, lng } = this.#mapEvent.latlng;
let workout;
// -> if running, create running object
if (type === 'running') {
// -> check if data is valid
const cadence = +inputCadence.value;
if (
!validInput(distance, duration, cadence) ||
!allPositive(distance, duration, cadence)
) {
return alert('Inputs have to be a positive number.');
}
workout = new Running([lat, lng], distance, duration, cadence);
}
// -> if cycling, create cycling object
if (type === 'cycling') {
const elevation = +inputElevation.value;
// -> check if data is valid
if (
!validInput(distance, duration, elevation) ||
!allPositive(distance, duration)
)
return alert('Inputs have to be a positive number.');
workout = new Cycling([lat, lng], distance, duration, elevation);
}
// -> adds workout to workout array
this.#workout.push(workout);
// -> render the workout
this._renderWorkoutMarker(workout);
// -> Render workout on list
this._renderWorkout(workout);
// -> hide the form
this._hideForm();
// -> save workouts to storage
this._setLocalStorage();
}
_renderWorkoutMarker(workout) {
// -> DISPLAY MAP MARKER ON SUBMIT
L.marker(workout.coords)
.addTo(this.#map)
.bindPopup(
L.popup({
minWidth: 250,
maxWidth: 100,
autoClose: false,
closeOnClick: false,
className: `${workout.type}-popup`,
})
)
.setPopupContent(
`${workout.type === 'cycling' ? 'π΄ββοΈ' : 'πββοΈ'} ${workout.description}`
)
.openPopup();
}
_renderWorkout(workout) {
let html = `
<li class="workout workout--${workout.type}" data-id="${workout.id}">
<h2 class="workout__title">${workout.description}</h2>
<div class="workout__details">
<span class="workout__icon">${
workout.type === 'cycling' ? 'π΄ββοΈ' : 'πββοΈ'
}</span>
<span class="workout__value">${workout.distance}</span>
<span class="workout__unit">km</span>
</div>
<div class="workout__details">
<span class="workout__icon">β±</span>
<span class="workout__value">${workout.duration}</span>
<span class="workout__unit">min</span>
</div>
`;
if (workout.type === 'running') {
html += `
<div class="workout__details">
<span class="workout__icon">β‘οΈ</span>
<span class="workout__value">${workout.pace.toFixed(1)}</span>
<span class="workout__unit">min/km</span>
</div>
<div class="workout__details">
<span class="workout__icon">π¦ΆπΌ</span>
<span class="workout__value">${workout.cadence.toFixed(1)}</span>
<span class="workout__unit">spm</span>
</div>
</li>
`;
}
if (workout.type === 'cycling') {
html += `
<div class="workout__details">
<span class="workout__icon">β‘οΈ</span>
<span class="workout__value">${workout.speed.toFixed(1)}</span>
<span class="workout__unit">km/h</span>
</div>
<div class="workout__details">
<span class="workout__icon">β°</span>
<span class="workout__value">${workout.elevation.toFixed(1)}</span>
<span class="workout__unit">m</span>
</div>
</li>
`;
}
form.insertAdjacentHTML('afterend', html);
}
_setLocalStorage() {
localStorage.setItem('workouts', JSON.stringify(this.#workout));
}
_getLocalStorage() {
const data = JSON.parse(localStorage.getItem('workouts'));
if (!data) return;
this.#workout = data;
console.log(typeof this.#workout);
this.#workout.forEach(work => {
this._renderWorkout(work);
});
}
}
It seems like the result of const data = JSON.parse(localStorage.getItem('workouts')); is not Array.
So you can check it as below
console.log(JSON.parse(localStorage.getItem('workouts')));
I have an issue with my Hangman app im creating.I'm stuck at the stage when im trying to program the letters reveal while clicking on them.
Hangman.js
import al from '../alphabet'
import {HangmanContext} from '../context/HangmanContext'
const Hangman = (props) =>{
const {password,displayGame,displayForm} = useContext(HangmanContext)
const [subject,setSubject] = password
const [gameDisplay,setGameDisplay] = displayGame
const [createSubjectDisplay,setCreateSubjectDisplay] = displayForm
let passwordArr = Array.from(subject)
const [hiddenPassword,changeHiddenPassword] = useState([''])
useEffect(() => {
let passwordArr = Array.from(subject)
console.log(passwordArr)
changeHiddenPassword(passwordArr.map(item => '_'))
},[subject]);
const chooseLetter = (e) => {
let letter = e.target.innerHTML
passwordArr.forEach((s,i) => {
if (s == letter){
console.log(hiddenPassword)
changeHiddenPassword(hiddenPassword.map((item,j) => {
if(j == i){
item = subject[i]
}
return item
}))
}
console.log(hiddenPassword)
})
}
const letters = al.map((letter) =>
<span onClick={chooseLetter}>{letter}</span>
)
return(
<div style={{display:gameDisplay}}>
<div className='password'>
{
passwordArr.map((item,i) => <span>{hiddenPassword[i]}</span>)
}
</div>
<div className='wrapper'>
<div className='pass_input'>Enter password:<input type='text' maxLength='30'/></div>
<div className='alphabet'> {letters} </div>
</div>
</div>
)
}
export default Hangman
In my chooseLetter function im trying to change hiddenPassword state that contains initially as many "_" as is the password length(which i have fixed in another state ) to the point where it has revealed clicked letter.It works fine when the password contain letters that doesn't repeat. When letters in the password are repeating, revealing them only works for the last of them and i want them to reveal all.
I am trying to filter through an array and display data based on the click event. There are three buttons that control different actions.
1.Button rollers display all the individuals who are rolling
2.Buttons non-rollers display lazy peeps who don't roll.
3.Buttons All display all the rollers and non-rollers.
I am trying to figure out if there is any way to display all rollers with the same filterRollers() function. I understand just resetting the state of rollingData back to the original value in a different function would do the trick but I am trying to limit to using one function. I will appreciate Any suggestion regarding the best practices . Thank you
var data =[
{ name="adam", task="roll" ,isrolling=true},
{ name="jack", task="roll" ,isrolling=false},
{ name="r2d2", task="roll" ,isrolling=true},
{ name="spidy", task="roll" ,isrolling=false}
]
this.state={
rollingState=data,
rollingData=data
}
filterRollers(status) {
let list = this.state.rollingState.filter(roll => {
return roll.isrolling === status
})
this.setState({
rollingData:list
})
}
render(){
return(
<div>
<button onClick={this.filterRollers(true)}>rollers </button>
<button onClick={this.filterRollers(false)}>non-rollers </button>
<button onClick={this.filterRollers(something)}> All </button>
{this.state.rollingData.map(roll=>{
return <Something roll={roll}/>
}
)}
</div>
)
}
When you want to show all the rollers, you can just call the function without any parameters. And then at the beginning of filterRollers function you can check if the parameter is undefined. If it is, just return all the data. If not, filter:
filterRollers(status) {
let list;
if(typeof status !== 'undefined'){
list = this.state.rollingState.filter(roll => {
return roll.isrolling === status
})
} else{
list = data.slice();
}
this.setState({
rollingData:list
})
}
Call the function like this, when you want to show all the rollers:
<button onClick={this.filterRollers()}> All </button>