ReactJS setState doesnt update anything - javascript

Im quite new to reactJS and ive been trying to create a table sorting based on this https://www.florin-pop.com/blog/2019/07/sort-table-data-with-react/. All works fine, did some changes and all, except my setState doesnt seem to update the my sorting. Here are some of my codes:
class TableView extends Component {
constructor(props) {
super(props)
this.state = {
students: [
{ name: 'Brian', age: 20, email: 'brian#hotmail.com' },
{ name: 'Kathy', age: 42, email: 'kathy#gmail.com' },
{ name: 'Donney', age: 50, email: 'donneylee#sjks.com' },
{ name: 'Cindy', age: 36, email: 'cindy#jflasjfl.com'}
]
}
this.headers = ['name', 'age', 'email'];
this.sortTypes = {
up: {
fn: (a, b) => { if (a.name < b.name) { return - 1 }}
},
down: {
fn: (a, b) => { if (a.name > b.name) { return 1 }}
},
default: {
fn: (a, b) => a
}
};
this.stateSort = {
currentSort: 'default'
};
}
onSortAsc = () => {
const { currentSort } = this.stateSort;
this.setState({ currentSort: 'up' }, () => {
console.log(currentSort);
});
}
renderTableData() {
const { currentSort } = this.stateSort;
const data = this.state.students;
return (
( data.length > 0 && (
[...data].sort(this.sortTypes[currentSort].fn).map(p => (
<tr key={p.name}>
<td>{p.name}</td>
<td>{p.age}</td>
<td>{p.email}</td>
</tr>
))
)
))
}
renderTableHeader() {
return<th key={index}>{key}<DropdownButton menuAlign="right" className="table-dropdown" title="">
<Dropdown.Item onClick={this.onSortAsc}>Sort A-Z</Dropdown.Item>
<Dropdown.Item href="#/action-2">Sort Z-A</Dropdown.Item>
</DropdownButton></th>
}
//The table
render() { //Whenever our class runs, render method will be called automatically, it may have already defined in the constructor behind the scene.
return (
<div>
<div id="table-view">
<button>Hide Fields</button>
<span class="more-btn"><FaEllipsisH /></span>
<div id="table-content">
<table id='funding-stage'>
<thead>
<tbody>
<tr>{this.renderTableHeader()}</tr>
{this.renderTableData()}
</tbody>
</thead>
</table>
</div>
</div>
</div>
)
}
};
export default Tableview;
Im not sure what went wrong. Ive tried different solutions but nothing seems to work.

The currentSort state should be in the state object (e.g you should access it as this.state.currentSort ) if you put it in another object ( stateSort ) and that object is the one in the state object, changing it will not cause update or rerender.
1 - remove
this.stateSort = {
currentSort: 'default'
};
2 - add currentSort to state object
this.state = {
students: [
{ name: 'Brian', age: 20, email: 'brian#hotmail.com' },
{ name: 'Kathy', age: 42, email: 'kathy#gmail.com' },
{ name: 'Donney', age: 50, email: 'donneylee#sjks.com' },
{ name: 'Cindy', age: 36, email: 'cindy#jflasjfl.com'}
],
currentSort: 'default'
}
3 - in onSortAsc function
onSortAsc = () => {
this.setState({ currentSort: 'up' }, () => {
console.log(currentSort);
});
}
and If that didn't help, update your code snippet and show the whole component to help you better.

Related

How to expand and collapse the table rows in plain react js. Show only one row if the description of the row is multiple and show the expand button

I am working on the table content which has 5 rows . few rows content description is same so I need to show only one row in this case and give expan button. when expand button is clicked it should show all the rows which has the same associated description. I am pasting the screenshot which I got as output .
In the above screenshot I've got the "-" button for all the rows which has same description. but I need only one "-"(collapse) button for "paytm" and one "-"button for "Paypal". and when they are clicked only one paytm, PayPal should be displayed.
let rows = [
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/04/2021' }
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/03/2020' }
},
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2021' }
},
{
id: { value: '' },
description: { value: 'Gpay' },
DueDate: { value: '04/03/2020' }
},
];
I am showing the table based on the lasted date and check if there exists any multiple same descriptions and putting them all in one object.
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = [
...(acc[current.description.value] || []),
current,
];
return acc;
}, {});
console.log(descriptionSortedArray);
and transforming the object based on latest date
const transformedRows = Object.keys(descriptionSortedArray).reduce(
(acc, current) => {
acc[current] = sortRowsByDate(descriptionSortedArray[current]);
return acc;
},
{}
);
// console.log(Object.keys(descriptionSortedArray));
console.log({ transformedRows });
and getting the key values for them by using object.keys and mapping over them.
x.[paytm:[], Gpay:[], PayPal :[]];
based on the inner array key length I am showing button (expand and collapse)if
x[paytm]>1 ?show button: without button
code is below
import React, { Component } from 'react';
import './style.css';
export default class App extends React.Component {
render() {
let rows = [
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/04/2021' }
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/03/2020' }
},
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2021' }
},
{
id: { value: '' },
description: { value: 'Gpay' },
DueDate: { value: '04/03/2020' }
},
];
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = [
...(acc[current.description.value] || []),
current,
];
return acc;
}, {});
console.log(descriptionSortedArray);
const sortRowsByDate = (rows) =>
rows.sort(
(a, b) => new Date(b.DueDate.value) - new Date(a.DueDate.value)
);
const transformedRows = Object.keys(descriptionSortedArray).reduce(
(acc, current) => {
acc[current] = sortRowsByDate(descriptionSortedArray[current]);
return acc;
},
{}
);
// console.log(Object.keys(descriptionSortedArray));
console.log({ transformedRows });
return (
<div>
<table>
<tr>
<th>id</th>
<th>description</th>
<th>duedate</th>
<th></th>
</tr>
{Object.keys(transformedRows).map((rowKey) => {
// console.log("rowKey===", rowKey)
// console.log(transformedRows[rowKey])
return (
<tbody>
{transformedRows[rowKey].length > 1
? transformedRows[rowKey].map((obj) => (
<tr>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td>{<button>-</button>}</td>
</tr>
))
: transformedRows[rowKey].map((obj) => (
<tr>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td></td>
</tr>
))}
</tbody>
);
})}
</table>
</div>
);
}
}
Please help in this. I need to show only one collapse button for the rows having same description(paytm is repeated show them only in one row give "expand" and "collapse" button). when even button is clicked it should be toggled. Please help
You can keep another field called visible along with your data array and toggle its value when clicked on the button.
Define a state to store the transformedRows
state = {
transformedRows: {}
};
Do the transformation like below in componentDidMount.
componentDidMount = () => {
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = {
...acc[current.description.value],
data: [...(acc[current.description.value]?.["data"] ?? []), current],
visible: false
};
return acc;
}, {});
const sortRowsByDate = (rows) =>
rows.sort(
(a, b) => new Date(b.DueDate.value) - new Date(a.DueDate.value.data)
);
const transformedRows = Object.keys(descriptionSortedArray).reduce(
(acc, current) => {
acc[current] = {
...descriptionSortedArray[current],
data: sortRowsByDate(descriptionSortedArray[current]["data"])
};
return acc;
},
{}
);
this.setState({ transformedRows });
};
Toggle the visible state when clicking on the button.
handleToggle = (entry, visibility) => {
this.setState((prevState) => {
return {
...prevState,
transformedRows: Object.fromEntries(
Object.entries(prevState.transformedRows).map(([key, value]) => {
if (key === entry) {
return [key, { ...value, visible: visibility }];
} else {
return [key, value];
}
})
)
};
});
};
Render rows as below.
<tbody>
{Object.entries(transformedRows).map(([key, { data, visible }]) => {
if (data.length > 1) {
return data.map((item, index) => (
<tr>
{(index === 0 || (index >= 1 && visible)) && (
<>
<td>{item.id.value}</td>
<td>{item.description.value}</td>
<td>{item.DueDate.value}</td>
</>
)}
{index === 0 && (
<td>
{
<button
onClick={() => {
this.handleToggle(key, !visible);
}}
>
toggle
</button>
}
</td>
)}
</tr>
));
} else {
return data.map(item => (
<tr>
<td>{item.id.value}</td>
<td>{item.description.value}</td>
<td>{item.DueDate.value}</td>
</tr>
));
}
})}
</tbody>
Create an accordion component as follow:
React accordion
Then use it as follow:
return (
<div>
<table>
<thead>
<tr>
<th>id</th>
<th>description</th>
<th>duedate</th>
<th></th>
</tr>
</thead>
{Object.keys(transformedRows).map((rowKey) => {
// console.log("rowKey===", rowKey)
// console.log(transformedRows[rowKey])
console.log(rowKey);
return (
<tbody key={rowKey}>
{transformedRows[rowKey].length > 1 ? (
<tr>
<td colSpan="4">
<Accordion label={rowKey}>
{transformedRows[rowKey].map((obj) => (
<div key={obj.id.value}>
<span>{obj.id.value}</span>
<span>{obj.description.value}</span>
<span>{obj.DueDate.value}</span>
<span>{<button>-</button>}</span>
</div>
))}
</Accordion>
</td>
</tr>
) : (
transformedRows[rowKey].map((obj) => (
<tr key={obj.id.value}>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td></td>
</tr>
))
)}
</tbody>
);
})}
</table>
</div>
);
Full code:
let rows = [
{
id: { value: '1' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '2' },
description: { value: 'paypal' },
DueDate: { value: '04/04/2021' },
},
{
id: { value: '3' },
description: { value: 'paypal' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '4' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2021' },
},
{
id: { value: '5' },
description: { value: 'Gpay' },
DueDate: { value: '04/03/2020' },
},
];
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = [...(acc[current.description.value] || []), current];
return acc;
}, {});
console.log(descriptionSortedArray);
const sortRowsByDate = (rows) =>
rows.sort((a, b) => new Date(b.DueDate.value) - new Date(a.DueDate.value));
const transformedRows = Object.keys(descriptionSortedArray).reduce((acc, current) => {
acc[current] = sortRowsByDate(descriptionSortedArray[current]);
return acc;
}, {});
return (
<div>
<table>
<thead>
<tr>
<th>id</th>
<th>description</th>
<th>duedate</th>
<th></th>
</tr>
</thead>
{Object.keys(transformedRows).map((rowKey) => {
// console.log("rowKey===", rowKey)
// console.log(transformedRows[rowKey])
console.log(rowKey);
return (
<tbody key={rowKey}>
{transformedRows[rowKey].length > 1 ? (
<tr>
<td colSpan="4">
<Accordion label={rowKey}>
{transformedRows[rowKey].map((obj) => (
<div key={obj.id.value}>
<span>{obj.id.value}</span>
<span>{obj.description.value}</span>
<span>{obj.DueDate.value}</span>
<span>{<button>-</button>}</span>
</div>
))}
</Accordion>
</td>
</tr>
) : (
transformedRows[rowKey].map((obj) => (
<tr key={obj.id.value}>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td></td>
</tr>
))
)}
</tbody>
);
})}
</table>
</div>
);

Create Complex & Dynamic rowspan in React

I try to make function that get an array of object and according to object in the array generate a table with dynamic rowspan.
I tried many solutions but none of them helped.
I tried this code,but I did not continue it because the beginning did not work well
const returnTabel = state => {
return state.map((item, index) => {
return (
<tr key={index}>
{Object.keys(item).map((key, index) => {
if (Array.isArray(item[key])) {
return item[key].map((object, index) => {
return Object.keys(object).map((i, index) => {
if (Array.isArray(object[i])) {
} else {
return (
<tr>
<td>{object[i]}</td>
</tr>
);
}
});
});
} else {
return (
<td rowSpan={2} key={index}>
{item[key]}
</td>
);
}
})}
</tr>
);
});};
Here is my data:
const state = [
{
name: 'Bill',
info: [
{
hobby: 'Practice',
field: [
{ type: 'Swim', hours: '6' },
{ type: 'Run', hours: '7' }
]
},
{
hobby: 'Listen to music',
field: [
{ type: 'Jazz', hours: '3' },
{ type: 'Electronic music', hours: '3' },
{ type: 'Hip hop', hours: '3' }
]
}
],
student: 'No'
},
{
name: 'John',
info: [
{
hobby: 'Practice',
field: [
{ type: 'Swim', hours: '1' },
{ type: 'Run', hours: '2' }
]
}
],
student: 'Yes'
}]
I want to make this table with my data
You can simplify the render mapping if you map the data to rows that look like:
[{"txt":"Bill","rowSpan":5},{"txt":"Practice","rowSpan":2},{"txt":"Swim"},{"txt":"6"},{"txt":"No","rowSpan":5}]
//OR
[null,{"txt":"Listen to music","rowSpan":3},{"txt":"Jazz"},{"txt":"3"},null]
//OR
[null,null,{"txt":"Run"},{"txt":"7"},null]
Then the render simplifies down to:
return (
<table border="1">
{rows.map(cells => (
<tr>
{cells.map(cell => cell && <td rowSpan={cell.rowSpan}>{cell.txt}</td>)}
</tr>
)
)}
</table>
);
Working example
const data=[{name:"Bill",info:[{hobby:"Practice",field:[{type:"Swim",hours:"6"},{type:"Run",hours:"7"}]},{hobby:"Listen to music",field:[{type:"Jazz",hours:"3"},{type:"Electronic music",hours:"3"},{type:"Hip hop",hours:"3"}]}],student:"No"},{name:"John",info:[{hobby:"Practice",field:[{type:"Swim",hours:"1"},{type:"Run",hours:"2"}]}],student:"Yes"}];
const rowData = data.reduce((a, { name, info, student }) => {
const rowSpan = info.reduce((a, { field }) => a + field.length, 0);
let [firstCell, lastCell] = [name, student].map(txt => ({ txt, rowSpan }));
info.forEach(({ hobby, field }, i) => {
const rowSpan = field.length;
let hobCell = { txt: hobby, rowSpan };
field.forEach((f, j) => {
const fieldCells = Object.values(f).map(txt => ({ txt }));
if (j > 0) {
hobCell = firstCell = lastCell = null;
}
const row = [firstCell, hobCell, ...fieldCells, lastCell];
a.push(row);
});
});
return a;
}, []);
console.log( rowData)
const Table = () => {
const [rows] = React.useState(rowData);
return (
<table border="1">
{rows.map((cells,i) => (
<tr key={i}>
{cells.map((cell,j) => cell && <td key={`${i}-${j}`} rowSpan={cell.rowSpan}>{cell.txt}</td>)}
</tr>
)
)}
</table>
);
};
// Render it
ReactDOM.render(
<Table />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

How to checkbox filtering in reactjs and handle state? and show the available item after the checkbox

I want to make a filter system using multiple checkbox. But when i checked one checkbox it filter the state but when i unchecked it how i can get back the all data in state . Also if i select multiple checkbox then it will filter from the filtered item.
Here is my code.
state = {
restaurant : [
{name: 'La mesa', cuisine: ['italian', 'indian']},
{name: 'Red Bull', cuisine: ['chiness', 'french']}
{name: 'Purnima', cuisine: ['thai', 'arabic']}
]
cuisine: [
{id: 1, name: 'italian'},
{id: 2, name: 'indian'},
{id: 3, name: 'chiness'}
{id: 4, name: 'french'},
{id: 4, name: 'arabic'},
]
}
handleCuisineFilter = (e) => {
if (e.target.checked) {
const filter =
this.state.restaurant.length &&
this.state.restaurant.filter((rest) => rest.cuisine.includes(e.target.value));
this.setState({ restaurant: filter });
} else {
Now when unchecked how i can get previous state???
}
};
render() {
return (
<div>
{this.state.cuisine.length && this.state.cuisine.map(
cuisine=> (<li>
<input
id={cuisine.id}
type='checkbox'
onChange={this.handleCuisineFilter}
name='check'
value={cuisine.name}
/>
{cuisine.name } {here will be count of number of restaurant}
</li>
))}
{this.state.restaurant.length && this.state.restaurant.map(rest=> <h5>rest.name</h5>)}
</div>
I tried to explain best via my code . Help me please. Thank you in advance
You have to keep track of checked state for each filter and then filter against all filters at once every time.
Here is the solution
EDIT
import React, { Component } from "react";
import "./App.css";
class App extends Component {
state = {
restaurant: [
{ name: "La mesa", cuisine: ["italian", "indian"] },
{ name: "Red Bull", cuisine: ["chiness", "french"] },
{ name: "Purnima", cuisine: ["thai", "arabic"] },
],
// maintain a checked state for each filter
cuisine: [
{ id: 1, name: "italian", checked: false },
{ id: 2, name: "indian", checked: false },
{ id: 3, name: "chiness", checked: false },
{ id: 4, name: "french", checked: false },
{ id: 5, name: "arabic", checked: false },
],
};
setFilter = (cuisine, flag) => {
this.setState((prevState) => ({
cuisine: prevState.cuisine.map((c) =>
// check state for the selected cuisine
c.id === cuisine.id ? { ...c, checked: flag } : c
),
}));
};
handleCuisineFilter = (e, cuisine) => {
if (e.target.checked) {
this.setFilter(cuisine, true);
} else {
this.setFilter(cuisine, false);
}
};
filterRestaurants = (restaurant) => {
const checkedFilters = this.state.cuisine.filter((c) => c.checked);
const noFiltersChecked = checkedFilters.length === 0;
if (noFiltersChecked) {
return true;
} else {
// EDITED:
const tmp = checkedFilters.reduce(
(hasRestaurantAllTheseCuisines, nextCuisine) =>
(hasRestaurantAllTheseCuisines =
hasRestaurantAllTheseCuisines &&
restaurant.cuisine.includes(nextCuisine.name)),
true
);
return tmp;
}
};
render() {
return (
<div>
{this.state.cuisine.length &&
this.state.cuisine.map((cuisine) => (
<li key={cuisine.id}>
<input
id={cuisine.id}
type="checkbox"
onChange={(e) => this.handleCuisineFilter(e, cuisine)}
name="check"
value={cuisine.name}
/>
{cuisine.name} {/* here will be count of number of restaurant */}
</li>
))}
{/* Use .filter() with cuisine state */}
{this.state.restaurant.length &&
this.state.restaurant
.filter(this.filterRestaurants)
.map((rest) => <h5 key={rest.name}>{rest.name}</h5>)}
</div>
);
}
}
export default App;
Edited the code. The only change was the filter check here
...
const tmp = checkedFilters.reduce(
(hasRestaurantAllTheseCuisines, nextCuisine) =>
(hasRestaurantAllTheseCuisines =
hasRestaurantAllTheseCuisines &&
restaurant.cuisine.includes(nextCuisine.name)),
true
);
...

react-sortablejs - Setting the 'onChange' method on an object with nested arrays

I'm using the react-sortablejs library.
When trying to move cards within the list. I get the error:
Cannot read property 'map' of undefined
I have a dense structure and it gets lost here. How to handle onChange so that I can see in the console that the order of the notes within the list has changed.
Demo here
import Sortable from 'react-sortablejs';
// Functional Component
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
onChange={(order, sortable, evt) => {
console.log(order)
onChange(order);
}}
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};
class App extends React.Component {
state = {
item: {
id: "abc123",
name: "AAA",
lists: [
{
id: "def456",
list_id: "654wer",
title: 'List1',
desc: "description",
listItems: [
{
id: "ghj678",
title: "ListItems1",
listItemsId: "88abf1"
},
{
id: "poi098",
title: "ListItems2",
listItemsId: "2a49f25"
},
{
id: "1oiwewedf098",
title: "ListItems3",
listItemsId: "1a49f25dsd8"
}
]
},
{
id: "1ef456",
list_id: "654wer",
title: 'List 2',
desc: "description",
listItems: [
{
id: "1hj678",
title: "ListItems4",
listItemsId: "18abf1"
},
{
id: "1oi098",
title: "ListItems5",
listItemsId: "1a49f25"
},
{
id: "1oiwewe098",
title: "ListItems6",
listItemsId: "1a49f25dsd"
}
]
},
{
id: "2ef456",
title: 'List 3',
list_id: "254wer",
desc: "description",
listItems: [
{
id: "2hj678",
title: "ListItems7",
listItemsId: "28abf1"
},
{
id: "2oi098",
title: "ListItems8",
listItemsId: "234a49f25"
},
{
id: "df098",
title: "ListItems9",
listItemsId: "1asd8"
}
]
}
]
}
};
render() {
const c = this.state.item['lists'].map(item => { return item.listItems});
return (
this.state.item['lists'].map(item => {
return (<div>
{item.title}
<SortableList
key={uniqueId()}
items={item}
onChange={(item) => {
console.log(item)
this.setState({item});
}}
>
</SortableList>
</div>)
})
)
}
};
Thanks in advance.
You have to update few changes in your code.
Update the SortableList function as below.
First pass data-id={val.id} in li and after that in onChange method you will receive the order with id. So based on that we are sorting the records.
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
onChange={(order, sortable, evt) => {
items.listItems.sort(function(a, b){
return order.indexOf(a.id) - order.indexOf(b.id);
});
onChange(items);
}}
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val.id}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};
Update the onChange event of App component.
onChange={(item) => {
let itemObj = {...this.state.item};
itemObj.lists.map(x=>{
if(x.id === item.id) x = item;
});
this.setState({itemObj});
}}
That's it!
Here is the working demo for you
https://stackblitz.com/edit/react-sortablejs-blzxwd
When remove the onChange event in the Sortable list, Its works.
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};

How to increment/decrement the likes and dislikes of the button in javascript?

i want to achieve increase number in likes and decrease number in
dislikes.
i have implemented the setState
enter image description here
import React, { Component } from 'react';
import { Row, Col, Card, CardHeader, CardBody, CardSubtitle, Button } from 'reactstrap';
import index from './index.css'
class MovieList extends Component {
constructor(props) {
super(props);
}
state ={
count:0
}
incrementMe = () => {
let newCount = this.state.count + 1
this.setState({
count: newCount
})
}
decrementMe = () => {
let newCount = this.state.count - 1
this.setState({
count: newCount
})
}
render () {
let { id, title, category, likes} = this.props.movie;
return (
<div>
<Row>
<Col>
<Card>
<CardHeader><strong>{title}</strong></CardHeader>
<CardBody>
<CardSubtitle>{category}</CardSubtitle>
<Button>👍 : {this.state.count}</Button>
<Button>👎 : {this.state.count}</Button>
<br />
<Button color="danger" onClick={() => this.props.removeMovie(id)}>Delete</Button>
</CardBody>
</Card>
</Col>
</Row>
</div>
)
}
}
export default MovieList;
the image i attached is the output of the present code
the following code is the movies list which i implemented into the
cards
import React, { Component } from 'react';
import { Container, Row, Col } from 'reactstrap';
import MovieList from './MovieList';
class Main extends Component {
constructor() {
super();
this.state = {
movies: [
{
id: '1',
title: 'Oceans 8',
category: 'Comedy',
likes: 4,
dislikes: 1
}, {
id: '2',
title: 'Midnight Sun',
category: 'Comedy',
likes: 2,
dislikes: 0
}, {
id: '3',
title: 'Les indestructibles 2',
category: 'Animation',
likes: 3,
dislikes: 1
}, {
id: '4',
title: 'Sans un bruit',
category: 'Thriller',
likes: 6,
dislikes: 6
}, {
id: '5',
title: 'Creed II',
category: 'Drame',
likes: 16,
dislikes: 2
}, {
id: '6',
title: 'Pulp Fiction',
category: 'Thriller',
likes: 11,
dislikes: 3
}, {
id: '7',
title: 'Pulp Fiction',
category: 'Thriller',
likes: 12333,
dislikes: 32
}, {
id: '8',
title: 'Seven',
category: 'Thriller',
likes: 2,
dislikes: 1
}, {
id: '9',
title: 'Inception',
category: 'Thriller',
likes: 2,
dislikes: 1
}, {
id: '10',
title: 'Gone Girl',
category: 'Thriller',
likes: 22,
dislikes: 12
}
]
}
}
removeMovie(id) {
this.setState({ movies: this.state.movies.filter(movie => movie.id !== id)});
}
render () {
let MovieLists = this.state.movies.map(movie => {
return (
<Col md="4">
<MovieList key={movie.id} removeMovie={this.removeMovie.bind(this)} movie={movie} />
</Col>
)
})
return (
<Container fluid>
<Row>
{MovieLists}
</Row>
</Container>
)
}
}
export default Main;
Please try to help me with the increase in likes and decrease in
dislikes(number with existing likes and dislikes)
I thought it might help you to see the code structured in a slightly different way as #Bharat23 mentioned earlier so I have created a Sandbox for you to have a look at that just does the like/dislike functionality in local state. In a real application you would validate that the user hadn't voted before and get the movie data from an external source that you update so this is very simplistic but I hope that it helps in some way.
https://codesandbox.io/s/wizardly-glitter-3ievf?fontsize=14
I'ts a little tricky to perform calculations in Javascript when the value can change to >0 0r 0 on the same field. So you have to carefully set the right conditions to prepare and take care of these situations.
incrementMe = () => {
var newCount = this.state.coun
function like () {
if (newCount !== 0) {
return newCount+=1
}
else {
return 1
}
}
this.setState({
count: like()
})
}
On dislike you can do the following.
decrementMe = () => {
var newCount = this.state.count
function dislike () {
if (newCount !== 0) {
return newCount-=1
}
else {
return -1
}
}
this.setState({
count: dislike()
})
}
I suggest you to write increment count of likes and dislikes into parent component only and pass those functions to child component.
<MovieList key={movie.id} removeMovie={this.removeMovie.bind(this)} movie={movie} likeMe={this.likeMe.bind(this)} dislikeMe={this.dislikeMe.bind(this)}/>
And function should be,
likeMe = (id) => {
var index = this.state.movies.findIndex(movie => movie.id === id);
if (index === -1) {
// handle error
} else {
this.setState({
movies: [
...this.state.movies.slice(0, index),
Object.assign({}, this.state.movies[index], { likes: this.state.movies[index].likes + 1 }),
...this.state.movies.slice(index + 1)
]
});
}
}
dislikeMe = (id) => {
var index = this.state.movies.findIndex(movie => movie.id === id);
if (index === -1) {
// handle error
} else {
this.setState({
movies: [
...this.state.movies.slice(0, index),
Object.assign({}, this.state.movies[index], { dislikes: this.state.movies[index].dislikes + 1 }),
...this.state.movies.slice(index + 1)
]
});
}
}
In child component,
<Button onClick={()=>this.props.likeMe(id)}>👍 : {likes}</Button>
<Button onClick={()=>this.props.dislikeMe(id)}>👎 : {dislikes}</Button>
Demo
Note: On dislike button press, it is common that we increase the count of dislike instead of decresing the count. I also did the same, I increases the count on dislike button press like { dislikes: this.state.movies[index].dislikes + 1 }. If you still go with anti-pattern and want to decrease the count do this { dislikes: this.state.movies[index].dislikes - 1 }, in this case you need to handle minus count.

Categories