refresh antd table on datasource change - javascript

I have a page that contains a searchbar component and an antd table component and I want my antd table to refresh whenever the datasource is changed or when I search in the searchbar. For now my table only updates when I refresh the page so I added a window.location.reload() to my onSearch function in order for it to work as intended but I want it to update without having to refresh the whole page. Is there a way to do that?
Here's my table.js
export default function Table() {
const [dataSource, setdataSource] = useState([]);
const [loading,setLoading] = useState(false);
useEffect(() => {
setLoading(true);
fetch(`${apiEndpoint}/api/managed-list`)
.then((response) => response.json())
.then((data) => {
setdataSource(data);
console.log(data)
})
.catch((err) => {
console.log(err);
})
.finally(() => {
setLoading(false);
});
}, []);
return (
<div>
<Table
bordered={true}
loading={loading}
columns={columns}
dataSource={dataSource}
pagination={true}
/>
</div>
)}
here's my searchbar.js
function SearchBar() {
const [searchedText, setSearchedText] = useState("");
let navigate = useNavigate();
const onSearch = () => {
navigate(`/search?q=${searchedText}`)
//find out a solution to update without refreshing
// window.location.reload()
console.log(searchedText)
fetch(`${apiEndpoint}/api/managed-list`,{
method: 'POST',
body: JSON.stringify({
content:searchedText
}), headers:{"Content-type":"application/json; charset=UTF-8",'Accept': 'application/json'}
}).then(response => response.json()).then(message=>console.log(message))
};
return (
<div>
<Input.Search
placeholder="Enter Company Name or keyword..."
onChange={(e) => {
setSearchedText(e.target.value);
}}
onSearch={onSearch}
onPressEnter={onSearch}
enterButton ></Input.Search>
</div>
);
}
export default SearchBar;

Related

unable to fetch a get request and print the output using fetch api

I am using react to get the data from an API using fetch API and print it but i was unable to retrieve data from after doing a fetch request. Here is the codelink. The input should be CC(C)(C)Br and the output is success message
import React, { useState } from "react";
import TextField from "#mui/material/TextField";
import Button from "#mui/material/Button";
export default function App() {
const [solutestate, setSolutestate] = useState("");
const [fetchData, setFetchData] = useState("");
console.log(solutestate);
console.log(fetchData);
let params = new URLSearchParams({
solute: solutestate
});
const onSubmit = (e) => {
fetch(
`https://fastapi-n7b7u.app/predict_two?${params}`,
{
method: "GET"
}
)
.then((res) => res.json())
.then((result) => {
setFetchData(result);
});
};
return (
<div className="App">
<>
<form noValidate onSubmit={onSubmit}>
<div>
Input: CC(C)(C)Br
<TextField
label="Solute"
variant="outlined"
onChange={(e) => setSolutestate(e.target.value)}
/>
<Button variant="contained">Submit</Button>
<TextField label="Result" variant="outlined" value={fetchData} />
</div>
</form>
</>
</div>
);
}
Couple of issues here.
Your submit button is not of type submit, so submit method is never called.
You will also want to put a preventDefault() on your submit handler, as the default will reload the page.
so changes are->
<Button type="submit" variant="contained">Submit</Button>
and
const onSubmit = (e) => {
e.preventDefault();
fetch(.....
Updated Sandbox
ps. This is not specifically about React, this is how forms work in
HTML.
const onSubmit = (e) => {
e.preventDefault()
let params = new URLSearchParams({
solute: solutestate
});
fetch(
`https://fastapi-ihub-n7b7u.ondigitalocean.app/predict_two?${params}`,
{
method: "GET",
content-type : "application/json"
}
)
.then((res) => res.json())
.then((result) => {
setFetchData(result);
});
};

Search function now working in React photo gallary

Working on a small application that takes a pexels api and displays photos dynamically. When I send the search request for my api to fectch based on the new params, it does actually update the page with new photos but not the ones based on the params. I though I got the search function correct, maybe it's cause I'm not using it in a useEffect? But if I did use it in a useEffect, I wouldn't be able to set it on the onClick handle. I tried to console.log the query I was getting from the onChange but it doesn't seem like it's getting the result. What am I doing wrong?
import { useState, useEffect } from 'react'
import pexelsApi from './components/pexelsApi'
import './App.css'
const App = () => {
const [images, setImages] = useState([]);
const [loading, setLoading] = useState(false);
const [nextPage, setNextPage] = useState(1);
const [perPage, setPerPage] = useState(25);
const [query, setQuery] = useState('');
const [error, setError] = useState('');
useEffect(() => {
const getImages = async () => {
setLoading(true);
await pexelsApi.get(`/v1/curated?page=${nextPage}&per_page=${perPage}`)
.then(res => {
setImages([...images, ...res.data.photos]);
setLoading(false);
}).catch(er => {
if (er.response) {
const error = er.response.status === 404 ? 'Page not found' : 'Something wrong has happened';
setError(error);
setLoading(false);
console.log(error);
}
});
}
getImages();
}, [nextPage, perPage]);
const handleLoadMoreClick = () => setNextPage(nextPage + 1)
const search = async (query) => {
setLoading(true);
await pexelsApi.get(`/v1/search?query=${query}&per_page=${perPage}`)
.then(res => {
setImages([...res.data.photos]);
console.log(res.data)
setLoading(false);
console.log(query)
})
}
if (!images) {
return <div>Loading</div>
}
return (
<>
<div>
<input type='text' onChange={(event) => setQuery(event.target.value)} />
<button onClick={search}>Search</button>
</div>
<div className='image-grid'>
{images.map((image) => <img key={image.id} src={image.src.original} alt={image.alt} />)}
</div>
<div className='load'>
{nextPage && <button onClick={handleLoadMoreClick}>Load More Photos</button>}
</div>
</>
)
};
export default App
import axios from 'axios';
export default axios.create({
baseURL: `https://api.pexels.com`,
headers: {
Authorization: process.env.REACT_APP_API_KEY
}
});
Your main issue is that you've set query as an argument to your search function but never pass anything. You can just remove the arg to have it use the query state instead but you'll then need to handle pagination...
// Helper functions
const getCuratedImages = () =>
pexelsApi.get("/v1/curated", {
params: {
page: nextPage,
per_page: perPage
}
}).then(r => r.data.photos)
const getSearchImages = (page = nextPage) =>
pexelsApi.get("/v1/search", {
params: {
query,
page,
per_page: perPage
}
}).then(r => r.data.photos)
// initial render effect
useEffect(() => {
setLoading(true)
getCuratedImages().then(photos => {
setImages(photos)
setLoading(false)
})
}, [])
// search onClick handler
const search = async () => {
setNextPage(1)
setLoading(true)
setImages(await getSearchImages(1)) // directly load page 1
setLoading(false)
}
// handle pagination parameter changes
useEffect(() => {
// only action for subsequent pages
if (nextPage > 1) {
setLoading(true)
const promise = query
? getSearchImages()
: getCuratedImages()
promise.then(photos => {
setImages([...images, ...photos])
setLoading(false)
})
}
}, [ nextPage ])
The reason I'm passing in page = 1 in the search function is because the setNextPage(1) won't have completed for that first page load.

How to add loader correctly while infinite scrolling?

I tried multiple ways to implement loading while fetching more data during infinite scrolling, but nothing worked properly, so I deleted loader; I have here state (with redux) named: loading but cannot write the logic of loading correctly. Could you please tell me how I can make it work?
Here I will provide with code:
import React, {useEffect} from 'react';
import { Link } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import {setAllUsers, setLoading, setPage} from '../redux/actions/actions';
import User from './User';
import '../styles/AllUsersList.css';
const AllUsersList = () => {
const allUsers = useSelector(state => state.setAllUsersReducer);
const page = useSelector(state => state.setPageReducer);
const loading = useSelector(state => state.setLoadingReducer);
const dispatch = useDispatch();
const fetchAllUsers = () => {
fetch(`${url}/${page}/15`)
.then(res => res.json())
.then(data => {
dispatch(setAllUsers(data.list));
})
.catch(err => console.log('Error message: ', err))
}
useEffect(() => {
fetchAllUsers();
}, [page])
const handleScroll = () => {
dispatch(setPage());
}
window.onscroll = function () {
if(window.innerHeight + document.documentElement.scrollTop === document.documentElement.offsetHeight) {
handleScroll();
}
}
return (
<div className="allUsersList">
{
allUsers ? (
allUsers.map((user, index) => (
<Link key={user.id} to={`/user/${user.id}`}>
<User name={user.name} lastName={user.lastName} prefix={user.prefix} title={user.title} img={user.imageUrl}/>
</Link>
))
) : (
<div> Loading... </div>
)
}
</div>
)
}
export default AllUsersList;
Your state loading would be set to true in your function fetchAllUsers the data and when the promise resolves it gets set to false.
Here's an example on how you would do it, you can adapt it to use a redux dispatcher to change loading state.
const loading = useState(false);
...
const fetchAllUsers = () => {
setLoading(true);
fetch(`${url}/${page}/15`)
.then(res => res.json())
.then(data => {
dispatch(setAllUsers(data.list));
})
.catch(err => console.log('Error message: ', err))
.finally(() => {
setLoading(false);
})
}
...
{
!loading ? (
allUsers.map((user, index) => (
<Link key={user.id} to={`/user/${user.id}`}>
<User name={user.name} lastName={user.lastName} prefix={user.prefix} title={user.title} img={user.imageUrl}/>
</Link>
))
) : (
<div> Loading... </div>
)
}

SetState Not Updating to fetch dynmically

I am learning react and I am trying to use a text input in a dynamic fetch request
My component is defined as ...
export default testpage = () => {
const [state, setState] = React.useState({})
let handleChange = (event) => {
setState({input: event.target.value})
}
async function buttonClick (input) {
console.log(state.input)
await fetch(`http://localhost:8080/api/${input}`)
.then(response => response.json())
.then(data => setState({...state, data}))
render(
<input type={'text'} onChange={handleChange.bind(this)} />
<Button onClick={() => buttonClick(state.input)}>test</Button>
)
}
My problem relates to useState updating asynchronously. If I enter a number ie. 4 into the input box and then click the button. The first time I click the button the fetch fails because undefined is passed to the fetch statement because the state hasn't been updated. If I click the button a second time the fetch succeeds. I have read into the useEffect hook but I am unable to figure out how to apply it to my situation.
Change the code to keep input's value directly in the state. The state value not need to be an object - it can be a string, number or null if that’s all you need.
const TestPage = () => {
const [postId, setPostId] = useState(null);
async function buttonClick() {
await fetch(`https://jsonplaceholder.typicode.com/posts/${postId}/comments`)
.then(response => response.json())
.then(data => console.log(data));
}
return (
<div>
<input onChange={e => setPostId(e.target.value)} />
<button onClick={buttonClick}>test</button>
</div>
);
};
The comonent already works as expected - it downloads data on every button click. It requires a display logic and a proper error handling, but I leave it for clarity.
You mentioned useEffect and here is the example of how you can use it:
function Test() {
const [postId, setPostId] = useState(null);
const [data, setData] = useState([]);
useEffect(() => {
async function getComments() {
if (Number(postId)) {
await fetch(
`https://jsonplaceholder.typicode.com/posts/${postId}/comments`
)
.then(response => response.json())
.then(data => setData(data));
} else { setData([]); }
}
getComments();
}, [postId]);
const comments = data
? data.map(comment => <li key={comment.id}>{comment.body}</li>)
: [];
return (
<div style={{ display: "flex", flexDirection: "column" }}>
<input type={"text"} onChange={e => setPostId(e.target.value)} />
{comments.length > 0 ? <ul>{comments}</ul> : <span>Write correct post ID (number 1-100)</span>}
</div>
);
}
But useEffect changes how you interact with your component. It runs an effect after rendering new state, meaning it runs right after changing input's value. Meaning, you don't need the <button> at all.
Because you begin request on button click it is better to use useCallback hook. It returns the same function on every button click as long as postId (input's value) doesn't change. You can use this function the same as you used buttonClick in first example:
const TestPage = () => {
const [postId, setPostId] = useState(null);
const handleClick = useCallback(() => {
async function getData() {
await fetch(
`https://jsonplaceholder.typicode.com/posts/${postId}/comments`
)
.then(response => response.json())
.then(data => console.log(data));
}
getData();
}, [postId]);
return (
<div>
<input onChange={e => setPostId(e.target.value)} />
<button onClick={handleClick}>test</button>
</div>
);
};

Issues with passing state between two separate components using React Hooks

So my issue is that I’m basically trying to pass the data that I have fetched from an API on my Home page, which is fetched and stored in the ‘geo’ variable upon pressing the submit button, and pass it onto the Maps page (accessed by pressing the Maps button after a postcode has been submitted), which will then use the latitude and longitude from ’geo’ (geo.result.latitude/longitude) to fetch from another API upon loading and display that data on the page. However, I’m having an issue with understanding how to pass state (or the values within the geo variable) between the two components/pages (Home and Maps) using hooks. I’m reasonably new to React, and very new to Hooks, so my understanding is very basic at the moment. Any help would be much appreciated :)
Home.js
import React, { useState, useEffect, useCallback } from 'react'
import { Link } from 'react-router-dom'
const Home = () => {
const [postCode, setPostcode] = useState({
pCode: ''
})
const [geo, setGeo] = useState([])
const fetchRequest = useCallback((e) => {
e.preventDefault()
fetch(`https://api.postcodes.io/postcodes/${postCode.pCode}`)
.then(res => res.json())
.then(res => setGeo(res))
console.log(geo)
}, [{ ...postCode }])
const handleChange = (e) => {
setPostcode({ ...postCode, pCode: e.target.value })
console.log(postCode)
}
return <section >
<div className='container'>
<form className="form" onSubmit={fetchRequest}>
<input className="input" type="text" placeholder="Text input" onChange={handleChange} />
< button>submit</button>
<Link className='button' to={{
pathname: '/maps'
}}>Map
</Link>
</form>
</div>
</section>
}
export default Home
Maps.js
const Maps = () => {
const [events, setEvents] = useState([])
const fetchRequest = useCallback(() => {
fetch(`https://api.list.co.uk/v1/events?near=${viewport.latitude},${viewport.longitude}/10`, {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
})
.then(res => res.json())
.then(res => setEvents(res))
}, [{ ...viewport }])
useEffect(() => {
fetch(`https://api.list.co.uk/v1/events?near=${geo.result.latitude},${geo.result.longitude}/10`, {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
})
.then(res => res.json())
.then(res => setEvents(res))
return () => console.log('Unmounting component')
}, [])
const [viewport, setViewport] = useState({
width: '100vw',
height: '100vh',
latitude: 51.45523,
longitude: -2.59665,
zoom: 13.5
})
if (events.length === 0) {
return <div>Loading...</div>
}
return <div>
<ReactMapGL mapboxApiAccessToken={TOKEN}
mapStyle="mapbox://styles/dredizzle/ck3owxclr138a1cqnzupab2hc"
{...viewport}
onViewportChange={viewport => {
setViewport(viewport)
}}
onClick={
fetchRequest
}
>
{events.map(event => (
<Popup
key={event.event_id}
latitude={event.schedules[0].place.lat}
longitude={event.schedules[0].place.lng}
>
</Popup>
))}
{/* <Popup latitude={51.45523} longitude={-2.59665}>
<div>event here</div>
</Popup> */}
<GeolocateControl
positionOptions={{ enableHighAccuracy: true }}
trackUserLocation={false}
/>
</ReactMapGL>
</div>
}
export default Maps
In the Maps component, I think you're overwriting the value of events when you repeat this line:
const [events, setEvents] = useState([])
You should just be able to reference this.state.events within the Maps component, and use this.setState() within Maps to add data to the events array from within the component.

Categories

Resources