React Add/Remove list of customize components - reactjs

I want my items could be add or removed.
Add items is ok, but remove one item will cause rest of items removed either.
I have tried the plain Object Array could be add/remove by these two functions, but the react element array can not work the same.
Here is I referenced the Delete function.
Here is my problem screen shot.
Here is code sandbox.
Anyone have suggestions?
Here is code:
import React, { useState, useRef, useCallback, useImperativeHandle } from 'react';
export default function List() {
const [itemList, setItemList] = useState([]);
const itemListRef = useRef([]);
const onDeleteProduct = useCallback(index => {
console.log("delete " + index);
setItemList(
itemList.filter((item, i) => i !== index)
);
})
function addSelectProduct() {
let index = itemList.length;
let newList = [];
newList.push(
<Item ref={r => itemListRef.current[index] = r}
number={index + 1} onDeleteProduct={() => onDeleteProduct(index)}
/>
);
setItemList(prevState => [...prevState,
...newList
]);
}
function allData() {
let len = itemListRef.current.lenth;
for(let i = 0; i < len; i++) {
console.log(itemListRef.current[i].getData());
}
}
return (
<>
<button onClick={addSelectProduct}>Add One</button>
<button onClick={allData}>show All data</button>
<table>
<thead>
<tr>
<th># No. </th>
<th>text </th>
<th>Operate</th>
</tr>
</thead>
<tbody>
{itemList}
</tbody>
</table>
</>
);
}
const Item = React.forwardRef(({ number, onDeleteProduct }, ref) => {
const [data, setData] = useState("");
useImperativeHandle(ref, () => ({
getData,
}));
const getData = () => {
return data;
}
return (
<tr key={number}>
<td>{number}</td>
<td><input value={data} onChange={e => setData(e.target.value)}/></td>
<td>
<button size="sm" variant="danger" onClick={() => onDeleteProduct(number)}>Delete</button>
</td>
</tr>
);
});

Looks like you don't have the last version of itemList. Maybe you should add itemList to the dependencies array of useCallback:
const onDeleteProduct = useCallback(index => {
console.log("delete " + index);
setItemList(
itemList.filter((item, i) => i !== index)
);
}, [itemList])
Furthermore, you should use a useCallback in addSelectProduct function too with its dependencies.

Related

React\Next.js how to get value from list element by click

I'm trying to get a value of list element by clicking on it, but the problem is that key, id, value not on a same element. I'll better show you. Here it is my list component:
import React, { useState, useEffect, useContext, useRef } from 'react';
import { Input } from '../';
import styles from "./Table.module.css";
import { Context } from "../../context/Context.js";
export const Table = (props) => {
const ref = useRef(null);
const [context, setContext] = useContext(Context);
const [search, setSearch] = useState("");
const [crypto, setCrypto] = useState([]);
const handleOnClick = (e, val) => { //THIS IS MY onClick FUNCTION
console.log("event",e.target.val)
console.log("ref",e.currentTarget.val);
setContext()//setContext((currentArray) => [...currentArray, inputValue])
};
useEffect(() => {
const fetchData = async () => {
await fetch(`https://api.coinstats.app/public/v1/coins?skip=0&limit=100¤cy=USD`)
.then((response) => {
return response.json();
})
.then((data) => {
setCrypto(data.coins)
})
};
fetchData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<div
{...props}
>
<h1>All Cryptocurrencies</h1>
<Input
type="text"
placeholder="Search..."
onChange={(e) => {
setSearch(e.target.value);
}}
/>
<table className={styles.table}>
<thead>
<tr>
<td>Rank</td>
<td>Name</td>
<td>Symbol</td>
<td>Total Supply</td>
<td>Market Cap</td>
<td>Price</td>
<td>Volume(24hrs)</td>
</tr>
</thead>
{/* Mapping all the cryptos */}
<tbody >
{/* Filtering to check for the searched crypto */}
{crypto
.filter((val) => {
return val.name.toLowerCase().includes(search.toLowerCase());
})
.map((val, id) => {
return (
<React.Fragment key={id}>
<tr id={id.toString()}>
<td>{val.rank}</td>
<td>
<a href={val.websiteUrl}>
<picture>
<img src={val.icon} alt="logo" width="30px" />
</picture>
</a>
<p>{val.name}</p>
</td>
<td className="symbol">{val.symbol}</td>
<td>${(val.totalSupply / 1000000).toFixed(0)} K</td>
<td>${(val.marketCap / 1000000000).toFixed(1)} B</td>
<td>${val.price < 0.01 ? val.price.toFixed(4) : val.price.toFixed(2) }</td>
<td>${(val.volume / 1000000000).toFixed(1)} B</td>
</tr>
</React.Fragment>//val.price.toFixed(4)
);
})}
</tbody>
</table>
</div>
);
};
And it looks like this:
So as you see I fetch the data from CoinGecko API. What do I expect: To get value (coin name f.e. "ethereum" by clicking on a list element)
Thank you in advance!

searchfilter with using react hook(useEffect / useState)

I am trying to create a searchBar.
When I type some value on input, I would like my listitems from github api to be re-listed with the value on searchBar.
import './App.css';
function App() {
const [datas, setDatas] = useState([]);
const [userid, setUserid] = useState('');
const inputChanged = (event) => {
setUserid(event.target.value)
}
const searchBar = () => {
}
useEffect(() => {
fetch('https://api.github.com/search/repositories?q=react')
.then(response => response.json())
.then(data => {
setDatas(data.items)
})
},[])
return (
<div className="App">
<h1>Repositories</h1>
<input id="searchInput"type="text" placeholder="search" name="search" value={userid} onChange={inputChanged}/>
<button onClick={searchBar}>Search</button>
<table>
<tbody>
<tr>
<th>Name</th>
<th>URL</th>
</tr>
{
datas.map((data, index) =>
<tr key={index}>
<td>{data.full_name}</td>
<td><a href={data.html_url}>{data.html_url}</a></td>
</tr>
)
}
</tbody>
</table>
</div>
);
}
export default App;
Here is my code and the image of the localhost
useEffect has an array at the end, when left empty what's in useEffect only update once. You can add variables to that array, to update when that variable changes.
Here you need to write: useEffect(your function,[userid]);

Creating Search functionality in reactJs for Table content

I am trying to build a search and sorting functionality for the table content. I don't want to use package as I am trying to learn and see how the react search work. I have the following that loads the content from payloads
import React, {useState, useEffect} from 'react'
import '../css/about.css';
import Pagination from '../components/Pagination'
function About() {
const [userData, setUserData] = useState([]);
const [loading , setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [postsPerPage, setPostsPerPage] = useState(5);
const [search, setSearch] = useState("");
async function getData()
{
let response = await fetch('https://api.github.com/users');
let data = await response.json();
// setUserData(data)
return data;
}
//call getData function
getData()
.then(data => console.log(data)
);//
useEffect(() => {
setLoading(true)
getData()
.then(
data => {
setUserData(data) }
)
.catch(error => {
console.log(error);
})
}, [])
// Get current posts
const indexOfLastPost = currentPage * postsPerPage;
const indexOfFirstPost = indexOfLastPost - postsPerPage;
const currentPosts = userData.slice(indexOfFirstPost, indexOfLastPost);
// changw page
const paginate = (pageNumber) => setCurrentPage(pageNumber);
// Search Table
const handleFilterChange = e => {
const value = e.target.value || undefined;
if( search !== "" && userData.login.indexOf(search.toLowerCase()) === -1 ) {
return null;
}
setSearch(value)
}
return (
<div className="container">
<div>
<input value={search}
onChange={handleFilterChange}
placeholder={"Search"}
/>
<table>
<thead>
<tr>
<td>id</td>
<td>avatar_url</td>
<td>events_url</td>
<td>followers_url</td>
<td>following_url</td>
<td>gists_url</td>
<td>gravatar_id</td>
<td>html_url</td>
<td>login</td>
<td>node_id</td>
<td>organizations_url</td>
<td>received_events_url</td>
<td>repos_url</td>
<td>site_admin</td>
<td>starred_url</td>
<td>subscriptions_url</td>
<td>type</td>
<td>url</td>
</tr>
</thead>
<tbody>
{
currentPosts.map((item, index) => (
<tr key={index}>
<td>{item.id}</td>
<td>{item.avatar_url}</td>
<td>{item.events_url}</td>
<td>{item.followers_url}</td>
<td>{item.following_url}</td>
<td>{item.gists_url}</td>
<td>{item.gravatar_id}</td>
<td>{item.html_url}</td>
<td>{item.login}</td>
<td>{item.node_id}</td>
<td>{item.organizations_url}</td>
<td>{item.received_events_url}</td>
<td>{item.repos_url}</td>
<td>{item.site_admin}</td>
<td>{item.starred_url}</td>
<td>{item.subscriptions_url}</td>
<td>{item.type}</td>
<td>{item.url}</td>
</tr>
))
}
</tbody>
</table>
<Pagination postsPerPage={postsPerPage} totalPosts={userData.length} paginate={paginate} />
</div>
</div>
)
}
export default About
The pagination code is listed below.
import React from 'react'
const Pagination = ({ postsPerPage, totalPosts, paginate }) => {
const pageNumbers = [];
for(let i = 1; i <= Math.ceil(totalPosts / postsPerPage); i++) {
pageNumbers.push(i);
}
return (
<div>
<ul className="pagination">
{pageNumbers.map(number => (
<li key={number} className="page-item">
<a onClick={() => paginate(number)}
href="#" className="page-link">
{number}
</a>
</li>
))}
</ul>
</div>
)
}
export default Pagination
I am think because I used .map within the tbody and the search isn't affecting the content. Though I have no error, only that nothing is displaying from search parameters.
I noticed you didn't create the function to handle the searching. You can use this generic approach which will search across the rows and the column and will match the cases.
function DataSearch(rows) {
const columns = rows[0] && Object.keys(rows[0]);
return rows.filter((row) =>
columns.some((column) => row[column].toString().toLowerCase().indexOf(search.toLowerCase()) > -1)
);
}
instantiate the function
const searchPosts = DataSearch(currentPosts);
Use the searchPosts on your .map function in tbody.

How to sort data in descending order and show in table, using functional components in React

I am working on React project, In that project, data is coming from the Backend, for that data
I need to do the sort. The data are only numbers. I am printing data in a console by using
useEffect Hook. Now I have to write two functions first function is to show data in Ascending
The order and the second function is to show data in Descending order. For this I have to use
Sort method But I don't know how to write this function using state. And I have to apply those
functions to sort Icon.
This is Form.js
import React, { useState, useEffect } from 'react';
import { Table } from 'reactstrap';
import Aumservice from '../../service/aum-service';
const GetAumListComponent = (props) => {
useEffect(() => {
(async function () {
const response = await Aumservice.getAum()
console.log(response.data.list.map(ele => ele.maxValue))
})()
}, [])
return (
<div>
<Aumcompanymodal data={editAumData} editSubmitFunction={editSubmitFunction} openModal={modal} closeModal={handleCancelModal}></Aumcompanymodal>
<IconContext.Provider
value={{ size: '25px' }}
>
<Table bordered>
<thead>
<tr>
<th>So No</th>
<th>Min</th>
<th>Max <i class="fas fa-sort fa-2x common"></i></th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{props.getAumState.map((currentValue, index) => {
return < tr key={index + 1} >
<th scope="row">{index + 1}</th>
<td>{currentValue.minValue}</td>
<td>{currentValue.maxValue}</td>
<td>
<MdEdit onClick={() => editMethod(currentValue)}></MdEdit>
</td>
</tr>
})}
</tbody>
</Table>
</IconContext.Provider>
</div >
)
}
export default GetAumListComponent
Let's assume, you have stored your data in state like this:
const [data, setData] = React.useState([])
Then you will create these two functions:
const sortAscending = () => {
let sortedData = data.sort((a, b) => a - b)
setData(sortedData)
}
const sortDescending = () => {
let sortedData = data.sort((a, b) => b - a)
setData(sortedData)
}
you can use useEffcet
function call orderBy -
orderBy('timestamp', 'desc')
useEffect(() => {
db.collection('messages').orderBy('timestamp', 'desc').onSnapshot(snapshot
=> {
setMessages(snapshot.docs.map(doc => doc.data()))
})

How to pass a state to another state in same component using functional component in React

I am working on a React project, In that project I am trying to sorting. In my component I have
Two buttons. The first button is Change to Min and the second button is Change to Max.
And in the same component I am showing the data that is coming from the backend.
Now If I click the button the sorting logic state has to apply to the data what I am showing by
Using the map method.
This is list.js
import React, { useState, useEffect } from 'react';
import { Table, Button } from 'reactstrap';
import Aumservice from '../../service/aum-service';
import { MdEdit } from 'react-icons/md';
import { IconContext } from "react-icons";
const List = (props) => {
const [sortData, setSortData] = useState(null)
const [data, setData] = useState([])
useEffect(() => {
(async function () {
const response = await Aumservice.getAum()
const dataResponse = response.data.list.map(ele => ele.maxValue)
setSortData(dataResponse)
setData(response.data.list)
})()
}, [])
const sortAscending = () => {
let sortedData = sortData.sort((a, b) => a - b)
console.log(sortedData)
setData(sortedData)
}
const sortDescending = () => {
let sortedData = sortData.sort((a, b) => b - a)
setData(sortedData)
}
return (
<div>
<IconContext.Provider
value={{ size: '25px' }}
>
<Table bordered>
<thead>
<tr>
<th>So No</th>
<th>Min</th>
<th>Max</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{setData.map((currentValue, index) => {
return < tr key={index + 1} >
<th scope="row">{index + 1}</th>
<td>{currentValue.minValue}</td>
<td>{currentValue.maxValue}</td>
</tr>
})}
</tbody>
</Table>
</IconContext.Provider>
<div className='min pr-5'>
<Button onClick={sortAscending} className='primary'>Change to Min</Button>
</div>
<div className='max'>
<Button className='secondary'>Change to Max</Button>
</div>
</div >
)
}
export default List
If I am not clear with my doubt please put a comment.
If I get it right, you want your data to be sorted by maxValue, in a way that depends on which button is clicked (ascending/descending).
There is a typo in the mapping element, instead of setData.map((.. you need data.map((...
An onClick event must be added at the second button with the sortDescending function.
You do not need a second variable sortData for sorting your data, you can sort the existing list that you get from the response.
According to the above conclusions, I have edited your code:
import React, { useState, useEffect } from 'react';
import { Table, Button } from 'reactstrap';
import Aumservice from '../../service/aum-service';
import { MdEdit } from 'react-icons/md';
import { IconContext } from "react-icons";
const List = (props) => {
const [data, setData] = useState([])
useEffect(() => {
(async function () {
const response = await Aumservice.getAum()
setData(response.data.list)
})()
}, [])
const sortAscending = () => {
let copyData = JSON.parse(JSON.stringify(data));
// If you want to sort by minValue,just change accordingly the below properties
let sortedData = copyData.sort((a, b) => (a.maxValue > b.maxValue) ? 1 : -1);
console.log(sortedData)
setData(sortedData)
}
const sortDescending = () => {
let copyData = JSON.parse(JSON.stringify(data));
// If you want to sort by minValue,just change accordingly the below properties
let sortedData = copyData.sort((a, b) => (a.maxValue < b.maxValue) ? 1 : -1);
console.log(sortedData)
setData(sortedData)
}
return (
<div>
<IconContext.Provider
value={{ size: '25px' }}
>
<Table bordered>
<thead>
<tr>
<th>So No</th>
<th>Min</th>
<th>Max</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{data.map((currentValue, index) => {
return <tr key={index + 1} >
<th scope="row">{index + 1}</th>
<td>{currentValue.minValue}</td>
<td>{currentValue.maxValue}</td>
</tr>
})}
</tbody>
</Table>
</IconContext.Provider>
<div className='min pr-5'>
<Button onClick={sortAscending} className='primary'>Change to Min</Button>
</div>
<div className='max'>
<Button onClick={sortDescending} className='secondary'>Change to Max</Button>
</div>
</div >
)
}
export default List

Resources