The delete function of my app is working fine, however it requires the user to manually refresh the page after the user click the delete button in order to see the new list of elements in my database. I would like to automatically refresh after the click event. I am using react hooks for this projects. However, I found one solution if I remove useEffect's [] but in my backend it shows, its requesting crazily. I don't know, is it wise to remove useffect's [ ]?
Here is the component where it fetches data from backend and passes the props to another component
import React, { useState, useEffect } from "react";
import axios from "axios";
import Table from "../Table/Table";
import "./Display.css";
const Display = () => {
const [state, setState] = useState({ students: [], count: "" });
const [searchItem, setsearchItem] = useState({
item: ""
});
const Search = e => {
setsearchItem({ item: e.target.value });
};
useEffect(() => {
axios
.get("/students")
.then(response => {
setState({
students: response.data.students,
count: response.data.count
});
})
.catch(function(error) {
console.log(error);
});
}, []); //If I remove this square brackets, it works
const nameFilter = state.students.filter(list => {
return list.name.toLowerCase().includes(searchItem.item.toLowerCase());
});
return (
<div>
<h3 align="center">Student tables</h3>
<p align="center">Total students: {state.count}</p>
<div className="input-body">
<div className="row">
<div className="input-field col s6">
<input placeholder="search student" onChange={Search} />
</div>
</div>
</div>
<table className="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Date of birth</th>
<th>Address</th>
<th>Zipcode</th>
<th>City</th>
<th>Phone</th>
<th>Email</th>
<th colSpan="2">Action</th>
</tr>
</thead>
{nameFilter.map((object, index) => {
return (
<tbody key={index}>
<Table obj={object} /> //In here I am passing the props to the another component.
</tbody>
);
})}
</table>
</div>
);
};
export default Display;
This is second component which receives the props.
import React, { useState } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
const Table = props => {
const removeData = () => {
axios
.delete("/students/" + props.obj.id)
.then(console.log("Deleted"))
.catch(err => console.log(err));
};
return (
<React.Fragment>
<tr>
<td>{props.obj.name}</td>
<td>{props.obj.birthday}</td>
<td>{props.obj.address}</td>
<td>{props.obj.zipcode}</td>
<td>{props.obj.city}</td>
<td>{props.obj.phone}</td>
<td>{props.obj.email}</td>
<td>
<Link
to={"/edit/" + props.obj.id}
className="waves-effect waves-light btn"
>
Edit
</Link>
</td>
<td>
<button onClick={removeData} className="waves-effect red btn ">
Remove
</button>
</td>
</tr>
</React.Fragment>
);
};
export default Table;
The [] in the useEffect hook is a dependency array to trigger the effect to run. If you want to trigger the effect (without it going off mercilessly), you can create a new variable that triggers that effect to run.
import React, { useState, useEffect } from "react";
import axios from "axios";
import Table from "../Table/Table";
import "./Display.css";
const Display = () => {
const [state, setState] = useState({ students: [], count: "" });
const [requestData, setRequestData] = useState(new Date());
const [searchItem, setsearchItem] = useState({
item: ""
});
const Search = e => {
setsearchItem({ item: e.target.value });
};
useEffect(() => {
axios
.get("/students")
.then(response => {
setState({
students: response.data.students,
count: response.data.count
});
})
.catch(function(error) {
console.log(error);
});
}, [requestData]);
const nameFilter = state.students.filter(list => {
return list.name.toLowerCase().includes(searchItem.item.toLowerCase());
});
return (
<div>
<h3 align="center">Student tables</h3>
<p align="center">Total students: {state.count}</p>
<div className="input-body">
<div className="row">
<div className="input-field col s6">
<input placeholder="search student" onChange={Search} />
</div>
</div>
</div>
<table className="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Date of birth</th>
<th>Address</th>
<th>Zipcode</th>
<th>City</th>
<th>Phone</th>
<th>Email</th>
<th colSpan="2">Action</th>
</tr>
</thead>
{nameFilter.map((object, index) => {
return (
<tbody key={index}>
<Table obj={object} setRequestData={setRequestData} />
</tbody>
);
})}
</table>
</div>
);
};
export default Display;
Then you can trigger it from your Table component:
import React, { useState } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
const Table = props => {
const removeData = () => {
axios
.delete("/students/" + props.obj.id)
.then(() => {
props.setRequestData(new Date());
})
.catch(err => console.log(err));
};
return (
<React.Fragment>
<tr>
<td>{props.obj.name}</td>
<td>{props.obj.birthday}</td>
<td>{props.obj.address}</td>
<td>{props.obj.zipcode}</td>
<td>{props.obj.city}</td>
<td>{props.obj.phone}</td>
<td>{props.obj.email}</td>
<td>
<Link
to={"/edit/" + props.obj.id}
className="waves-effect waves-light btn"
>
Edit
</Link>
</td>
<td>
<button onClick={removeData} className="waves-effect red btn ">
Remove
</button>
</td>
</tr>
</React.Fragment>
);
};
export default Table;
Not sure if helps but you can always remove the item from the current array, so a refresh is not needed, for example you can pass as props a function that receives an id and then filter the students array to exclude the element that matches with that id and then update the state with the new array and count properties, something like this
In your parent:
const Display = () => {
const [state, setState] = useState({ students: [], count: "" });
const deleteItem = (id) => {
const newStudents = state.students.filter(student => student.id !== id)
const newCount = newStudents.length;
setState({ students: newStudents, count: newCount })
}
// Rest of the code
}
Now pass that function to your child component.
<Table obj={object} deleteItem={deleteItem} />
In the child component just modify your removeData method to add the deleteItem prop:
const Table = props => {
const removeData = () => {
axios
.delete("/students/" + props.obj.id)
.then(console.log("Deleted"))
.catch(err => console.log(err));
// Now if your request succeeds call the function to remove the item from the students state array
props.deleteItem(props.obj.id);
};
// Rest of the code
}
I know this does not answer your question, but when you're working with react or it is better to do this computations and filters on the app side, like in this case that even though the record was deleted from the db we also removed the record from the student state object and there's no need to refresh the page.
Remember, you're creating a single page application, so we want the nicest experience for the user without refreshing the page for every action the user makes.
Have a look at this
import React, { useState } from "react";
const Display = () => {
const [refresh, setRefresh] = useState(false)
const delete=() => {
// ................. //delete logic
reload ? setRefresh(false) : setRefresh(true) //toggle just to change state
}
useEffect(() => {
}, [reload]); //inject as dependency
}
Related
How to use React hooks to show a only updated data in table ?
Now I can display all the information. But I want to display the data in a table. When the data in firestore is updated, the data will be displayed on the website. so how to use a React Hook on this code to show information to display only a updated data ?
import React, { useEffect, useState } from "react";
import { Button } from "react-bootstrap";
import Table from 'react-bootstrap/Table';
import BookDataService from "../../services/book.services";
import "./table.css";
const tableList = () => {
const [profile, setBooks] = useState([]);
useEffect(() => {
getBooks();
}, []);
const getBooks = async () => {
const data = await BookDataService.getAllBooks();
console.log(data.docs);
setBooks(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
};
return (
<>
<div className="mb-4">
<Button variant="success edit" onClick={getBooks}>
Refresh
</Button>
</div>
{/* <pre>{JSON.stringify(books, undefined, 2)}</pre>} */}
<Table striped bordered hover variant="dark" size="md">
<thead>
<tr>
<th>RollNo</th>
<th>Name</th>
<th>Student ID</th>
<th>Subject</th>
<th>Room</th>
<th>Date</th>
<th>Time</th>
{/*<th>Action</th>*/}
</tr>
</thead>
<tbody>
{profile.map((doc, index) => {
const timestamp = { nanoseconds: doc.timeStamp.nanoseconds, seconds: doc.timeStamp.seconds }
const firebasetime = new Date(
timestamp.seconds * 1000 + timestamp.nanoseconds / 1000000,
);
const date = firebasetime.toDateString();
const timeStamp = firebasetime.toLocaleTimeString();
console.log(date, timeStamp);
return (
<tr key={doc.id}>
<td>{index + 1}</td>
<td>{doc.name}</td>
<td>{doc.sid}</td>
<td>{doc.Subject}</td>
<td>{doc.Room}</td>
<td>{date}</td>
<td>{timeStamp}</td>
</tr>
);
})}
</tbody>
</Table>
</>
);
};
export default tableList;
Here is the simple example for show only updated data:
import { useState, useEffect } from 'react';
const SimpleTable = () => {
const [data, setData] = useState([]);
useEffect(() => {
const fetchData = async () => {
const response = await fetch('https://samplejsonholder.test.com/test');
const data = await response.json();
setData(data);
//You can replace this with data source or api call
};
fetchData();
}, []);
useEffect(() => {
// Every time the 'data' state updates, this will run.
console.log('data updated:', data);
}, [data]);
return (
...
);
};
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!
I need to send the data to "Search" Component from "SearchingData" Component. SearchingData is the child of searchData, Here I need to send the "datacame" variable data to Search Component,Can anyone Help me out this, Thanks in Advance.
I need to access that "datacame" variable data to next Search Component, So Now How i can send that Data Search Component,Can anyone Help me out this, Thanks in Advance...
import React, { ChangeEvent, useState } from "react";
type searchData = {
handleSearch: (e: ChangeEvent<HTMLInputElement>) => void;
seardhingDTata: any;
seardhDTata: string;
};
const SearchingData: React.FC<searchData> = ({
handleSearch,
seardhingDTata,
seardhDTata,
}) => {
const UpdateData = (e: ChangeEvent<HTMLInputElement>) => {
handleSearch(e);
};
const [datacame, setdatacame] = useState(seardhDTata);
const serachData = () => {
let defaultData = seardhingDTata;
const filterdserachData = seardhDTata
? defaultData.filter((use: any) =>
use.UserName.toLowerCase().startsWith(seardhDTata)
)
: defaultData;
//console.log(filterdserachData);
setdatacame(filterdserachData);
};
return (
<React.Fragment>
<div>
<input type="text" onChange={UpdateData} />
<button className="btn btn-blue btn-sm" onClick={serachData}>
Serach
</button>
</div>
</React.Fragment>
);
};
export default SearchingData;
import React, { ChangeEvent } from "react";
import { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import SearchingData from "./SearchingData";
const Search: React.FC = () => {
let dispatch = useDispatch();
//Read the Data from Store
let readingStateData: searchReducsers.ISearch = useSelector(
(state: { searchingData: searchReducsers.ISearch }) => {
return state.searchingData;
}
);
// Update the Data
useEffect(() => {
//console.log(readingStateData.search)
dispatch(searchActions.fetchUser());
}, []);
const [seardhDTata, setseardhDTata] = useState("");
// const [searchText, setsearchText] = useState('');
const handlesearching = (e: ChangeEvent<HTMLInputElement>) => {
//console.log(e.target.value);
setseardhDTata(e.target.value);
};
const defaultData = readingStateData.search;
return (
<React.Fragment>
<div className="container mt-3">
<div className="row">
<div className="col-md-3">
<div className="card"></div>
</div>
</div>
</div>
<SearchingData
handleSearch={handlesearching}
seardhingDTata={defaultData}
seardhDTata={seardhDTata}
/>
<table className="table table-hover text-center table-primary">
<thead className="text-black">
<tr>
<th>UserName</th>
<th>Phone</th>
<th>Email</th>
<th>Gender</th>
</tr>
</thead>
<tbody>
<React.Fragment>
{defaultData.map((user) => {
return (
<tr>
<td>{user.UserName}</td>
<td>{user.PhoneNumber}</td>
<td>{user.email}</td>
<td>{user.gender}</td>
</tr>
);
})}
</React.Fragment>
</tbody>
</table>
</React.Fragment>
);
};
export default Search;
Have a state in the Search component which updates the state when we click on the button on the SearchingData. Now use this state to filter the data.
Searching Data Component
import React, { ChangeEvent, useState } from "react";
type searchData = {
setSearchText: (searchText: string) => void;
};
const SearchingData: React.FC<searchData> = ({
handleSearch,
}) => {
const [ searchInput, setSearchInput ] = useState('')
const serachData = () => {
setSearchText(searchInput);
};
return (
<React.Fragment>
<div>
<input type="text" value={searchInput} onChange={(e) => setSearchInput(e.target.value) } />
<button className="btn btn-blue btn-sm" onClick={serachData}>
Serach
</button>
</div>
</React.Fragment>
);
};
export default SearchingData;
Search Component
import React, { ChangeEvent } from "react";
import { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import SearchingData from "./SearchingData";
const Search: React.FC = () => {
let dispatch = useDispatch();
const [searchQuery, setSearchQuery] = useState("");
//Read the Data from Store
let readingStateData: searchReducsers.ISearch = useSelector(
(state: { searchingData: searchReducsers.ISearch }) => {
return state.searchingData;
}
);
// Update the Data
useEffect(() => {
//console.log(readingStateData.search)
dispatch(searchActions.fetchUser());
}, []);
const handlesearching = (searchText: string) => {
//console.log(e.target.value);
setSearchQuery(searchText);
};
const dataToDisplay = searchQuery.trim().length > 0 ? readingStateData.search.filter((use: any) =>
use.UserName.toLowerCase().startsWith(seardhDTata)
) : readingStateData.search;
return (
<React.Fragment>
<div className="container mt-3">
<div className="row">
<div className="col-md-3">
<div className="card"></div>
</div>
</div>
</div>
<SearchingData
setSearchText={handlesearching}
/>
<table className="table table-hover text-center table-primary">
<thead className="text-black">
<tr>
<th>UserName</th>
<th>Phone</th>
<th>Email</th>
<th>Gender</th>
</tr>
</thead>
<tbody>
<React.Fragment>
{dataToDisplay.map((user) => {
return (
<tr>
<td>{user.UserName}</td>
<td>{user.PhoneNumber}</td>
<td>{user.email}</td>
<td>{user.gender}</td>
</tr>
);
})}
</React.Fragment>
</tbody>
</table>
</React.Fragment>
);
};
export default Search;
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]);
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