Not Rendering Card - React - reactjs

I'm new to React, and I would like to know if someone can help me?
I'm trying to use useEffect and State to manipulate the API.
But the cards are not rendering.
Sometimes all the cards are rendering, other times not.. and they always come on a different order even after sorting them :( Can you help me?
App.js
/* eslint-disable react-hooks/exhaustive-deps */
import React, { useState, useEffect } from "react";
import PlayerList from "./PlayerList";
import axios from "axios";
function App() {
const Team = [
...
];
const Team2 = [
...
];
const Team3 = [
...
];
const teamForLoop = [Team, Team2, Team3];
const [allPlayers, setAllPlayers] = useState([]);
const [team, setTeam] = useState([]);
const [allTeams] = useState(teamForLoop);
const [loading, setLoading] = useState(true);
useEffect(() => {
const playerInfo = async () => {
setLoading(true);
allTeams.map(async (teamArray) => {
setTeam([]);
teamArray.map(async (player) => {
let playerName = player.split(" ");
const result = await axios.get(
`https://www.thesportsdb.com/api/v1/json/2/searchplayers.php?p=${playerName[0]}%20${playerName[1]}`
);
if (result.data.player === null) {
setTeam((state) => {
return [...state];
});
} else {
setTeam((state) => {
return [...state, result.data.player[0]];
});
}
});
setAllPlayers(team);
});
setLoading(false);
};
playerInfo();
}, [allTeams]);
if (loading) return "...Loading...";
return (
<>
<PlayerList allPlayers={allPlayers} />
</>
);
}
export default App;
PlayerList.js
import React from "react";
export default function PlayerList({ allPlayers }) {
const myData = []
.concat(allPlayers)
.sort((a, b) => (a.strNumber > b.strNumber ? 1 : -1))
.sort((a, b) => (a.idTeam !== b.idTeam ? 1 : -1));
return (
<div>
{myData.map((player, index) => (
<div key={index}>
<div className="playerCard">
<img
className="playerImage"
src={player.strCutout}
alt={`${player.strPlayer}`}
/>
<h1 className="playerName">{player.strPlayer}</h1>
<h2 className="playerNumber">{player.strNumber}</h2>
</div>
</div>
))}
</div>
);
}
Codesandbox link:
"https://codesandbox.io/s/busy-orla-v872kt?file=/src/App.js"

Related

How optimize little code React "RandomImage" from array with onclick

I make a little code for take array images and show one and change it with click, but I think that code can be more optimized, especialy the second useState but I dont know how.
import React, { useEffect, useState } from 'react';
const apiURL = 'https://picsum.photos/v2/list?page=2&limit=100';
export default function Image() {
function random(mn, mx) {
return Math.random() * (mx - mn) + mn;
}
const [gifs, setgifs] = useState([]);
useEffect(function () {
console.log('test');
fetch(apiURL)
.then((res) => res.json())
.then((response) => {
const gifs = response.map((image) => image.download_url);
setgifs(gifs);
});
}, []);
let imagenaleatoria = gifs[Math.floor(random(1, gifs.length))];
const [imagenactual, nuevaimagen] = useState();
return (
<div className='App'>
<section className='App-header'>
<div className='caja'>
<img
onClick={() => {
nuevaimagen(gifs[Math.floor(random(1, gifs.length))]);
}}
src={imagenaleatoria}
></img>
</div>
</section>
</div>
);
}
Thanks so much.
I thought I just rewrite your code snippet and add comments so you understand what and why
import { useState, useEffect } from "react";
const apiURL = "https://picsum.photos/v2/list?page=2&limit=100";
// has no acces to state so there is no need to create this funtion isde the RandomImage component
export const getRandomIndex = (min, max) => {
return Math.floor(Math.random() * (max - min) + min);
};
export const RandomImage = () => {
const [gifs, setGifs] = useState([]);
const [randomIndex, setRandomIndex] = useState(null);
// runs only after the first render
useEffect(function () {
console.log("test");
fetch(apiURL)
.then((res) => res.json())
.then((response) => {
const gifs = response.map((image) => image.download_url);
setGifs(gifs);
setRandomIndex(getRandomIndex(0, gifs.length));
});
}, []);
// just sets an random index
const handleClick = (event) => {
setRandomIndex(getRandomIndex(0, gifs.length));
};
return (
<div className="App">
<section className="App-header">
<div className="caja">
{!gifs.length ? (
'Loading...'
) : (
<img onClick={handleClick} src={gifs[randomIndex]} />
)}
</div>
</section>
</div>
);
};

useEffect only runs on hot reload

I have a parent/child component where when there is a swipe event occurring in the child the parent component should fetch a new profile. The problem is the useEffect in the child component to set up the eventListeneners currently is not running, only occasionally on hot-reload which in reality should run basically every time.
Child component
function Profile(props: any) {
const [name] = useState(`${props.profile.name.title} ${props.profile.name.first} ${props.profile.name.last}`);
const [swiped, setSwiped] = useState(0)
const backgroundImage = {
backgroundImage: `url(${props.profile.picture.large})`
};
const cardRef = useRef<HTMLDivElement>(null);
const card = cardRef.current
let startX:any = null;
function unify (e:any) { return e.changedTouches ? e.changedTouches[0] : e };
function lock (e:any) { if (card) {startX = unify(e).clientX; console.log(startX)} }
function move (e: any) {
console.log('move')
if(startX) {
let differenceX = unify(e).clientX - startX, sign = Math.sign(differenceX);
if(sign < 0 || sign > 0) {
setSwiped((swiped) => swiped +1)
props.parentCallback(swiped);
startX = null
}
}
}
// Following code block does not work
useEffect(() => {
if (card) {
console.log(card)
card.addEventListener('mousedown', lock, false);
card.addEventListener('touchstart', lock, false);
card.addEventListener('mouseup', move, false);
card.addEventListener('touchend', move, false);
}
})
return (
<div>
<h1 className="heading-1">{name}</h1>
<div ref={cardRef} className="card" style={backgroundImage}>
</div>
</div>
);
}
Parent component
function Profiles() {
const [error, setError] = useState<any>(null);
const [isLoaded, setIsLoaded] = useState(false);
const [profiles, setProfiles] = useState<any[]>([]);
const [swiped, setSwiped] = useState(0)
useEffect(() => {
getProfiles()
}, [swiped])
const callback = useCallback((swiped) => {
setSwiped(swiped);
console.log(swiped);
}, []);
const getProfiles = () => {
fetch("https://randomuser.me/api/")
.then(res => res.json())
.then(
(result) => {
setIsLoaded(true);
setProfiles(result.results);
},
(error) => {
setIsLoaded(true);
setError(error);
}
)
}
if (error) {
return <h1 className="heading-1">Error: {error.message}</h1>;
} else if (!isLoaded) {
return <h1 className="heading-1">Loading...</h1>;
} else {
return (
<div id="board">
{profiles.map(profile => (
<Profile key={profile.id.value} profile={profile} parentCallback={callback}/>
))}
</div>
);
}
}
If you want the parent components swiped state to change, you need to pass "setSwiped" from the parent to the child compenent. You will also need to pass "swiped" to the child to use its current value to calculate the new value. I'm going to assume you declared the useState in the child component trying to set the parents state of the same name, so I'm going to remove that useState Declaration in the child altogether.
Here's an example of passing the setSwiped method and swiped value to the child:
PARENT
import React, {useState, useEffect, useCallback} from 'react';
import './Index.css';
import Profile from './Profile'
function Profiles() {
const [error, setError] = useState<any>(null);
const [isLoaded, setIsLoaded] = useState(false);
const [profiles, setProfiles] = useState<any[]>([]);
const [swiped, setSwiped] = useState(0)
useEffect(() => {
getProfiles()
}, [swiped])
const callback = useCallback((swiped) => {
setSwiped(swiped);
console.log(swiped);
}, []);
const getProfiles = () => {
fetch("https://randomuser.me/api/")
.then(res => res.json())
.then(
(result) => {
setIsLoaded(true);
setProfiles(result.results);
},
(error) => {
setIsLoaded(true);
setError(error);
}
)
}
if (error) {
return <h1 className="heading-1">Error: {error.message}</h1>;
} else if (!isLoaded) {
return <h1 className="heading-1">Loading...</h1>;
} else {
return (
<div id="board">
{profiles.map(profile => (
<Profile key={profile.id.value} profile={profile} parentCallback={callback} setSwiped={setSwiped} swiped={swiped}/>
))}
</div>
);
}
}
export default Profiles;
CHILD
import React, {useState, useRef, useEffect } from 'react';
import './Index.css';
function Profile(props: any) {
const [name] = useState(`${props.profile.name.title} ${props.profile.name.first} ${props.profile.name.last}`);
const backgroundImage = {
backgroundImage: `url(${props.profile.picture.large})`
};
const cardRef = useRef<HTMLDivElement>(null);
const card = cardRef.current
let startX:any = null;
function unify (e:any) { return e.changedTouches ? e.changedTouches[0] : e };
function lock (e:any) { if (card) {startX = unify(e).clientX; console.log(startX)} }
function move (e: any) {
console.log('move')
if(startX) {
let differenceX = unify(e).clientX - startX, sign = Math.sign(differenceX);
if(sign < 0 || sign > 0) {
props.setSwiped((props.swiped) => props.swiped +1)
props.parentCallback(props.swiped);
startX = null
}
}
}
useEffect(() => {
if (card) {
console.log(card)
card.addEventListener('mousedown', lock, false);
card.addEventListener('touchstart', lock, false);
card.addEventListener('mouseup', move, false);
card.addEventListener('touchend', move, false);
}
})
return (
<div>
<h1 className="heading-1">{name}</h1>
<div ref={cardRef} className="card" style={backgroundImage}>
</div>
</div>
);
}
export default Profile;
I'm hoping I didn't miss anything here.
Best of luck.

useEffect dosn't save data in localstorage

I have a simple app, sorta for chat purpuses. I fetch data from static file in json format. So this app shows all the messages from that file but also I want to edit the messeges, delete them and add via local storage. For that I used useEffect, but after refresh all the changes I do disappear.
This is my component:
export const WorkChat = (props) => {
const [messageValue, setMessageValue] = useState('');
const [edit, setEdit] = useState(null);
const [editmessageValue, setMessageEditValue] = useState('')
const submitMessage = () => {
const newMessage = {
id: Math.floor(Math.random() * 10000),
message: messageValue
}
props.addMessage(newMessage);
setMessageValue('')
}
const removeMsg = (id) => {
props.deleteMessage(id)
}
const goToEditMode = (message) => {
setEdit(message.id);
setMessageEditValue(message.message)
}
const saveChanges = (id) => {
const newMessagesArray = props.messages.map(m => {
if(m.id === id){
m.message = editmessageValue
}
return m
})
props.updateMessage(newMessagesArray);
setEdit(null)
}
useEffect(()=> {
let data = localStorage.getItem('work-messages');
if(data){
props.setMessages(JSON.parse(data))
}
}, []);
useEffect(()=> {
localStorage.setItem('work-messages', JSON.stringify(props.messages))
},[props.messages])
return (
<div className={s.workChatContainer}>
<input className={s.workInput} placeholder='Enter work message...' onChange={(e)=> setMessageValue(e.target.value)} value={messageValue}/>
<button className={`${s.btn} ${s.sendBtn}`} onClick={()=>submitMessage()}><SendIcon style={{fontSize: 20}}/></button>
<div>
{props.messages.map(m => (
<div key={m.id} className={s.messages}>
{edit !== m.id ? <div>
<span className={s.message}>{m.message}</span>
<button className={`${s.btn} ${s.deleteBtn}`} onClick={()=> removeMsg(m.id)}><DeleteOutlineIcon style={{fontSize: 15}}/></button>
<button className={`${s.btn} ${s.editBtn}`} onClick={()=> goToEditMode(m)}><EditIcon style={{fontSize: 15}}/></button>
</div>
:
<form>
<input className={s.editInput} value={editmessageValue} onChange={(e)=> setMessageEditValue(e.target.value)}/>
<button className={`${s.btn} ${s.saveBtn}`} onClick={()=> saveChanges(m.id)}><BeenhereIcon style={{fontSize: 15}}/></button>
</form>
}
</div>
))}
</div>
</div>
)
}
Just in case, this is my container component:
import { connect } from "react-redux"
import { setFloodMessagesAC, addFloodMessageAC, deleteFloodMessageAC, upadateMessageAC } from "../../redux/flood-reducer"
import { FloodChat } from "./FloodChat"
import { useEffect } from 'react'
import data from '../../StaticState/dataForFlood.json'
const FloodChatApiContainer = (props) => {
useEffect(()=> {
props.setFloodMessages(data)
}, [])
return <FloodChat messages={props.messages}
setFloodMessages={props.setFloodMessages}
addFloodMessage={props.addFloodMessage}
deleteFloodMessage={props.deleteFloodMessage}
upadateMessage={props.upadateMessage}
/>
}
const mapStateToProps = (state) => ({
messages: state.flood.messages
})
export const FloodChatContainer = connect(mapStateToProps, {
setFloodMessages: setFloodMessagesAC,
addFloodMessage: addFloodMessageAC,
deleteFloodMessage: deleteFloodMessageAC,
upadateMessage: upadateMessageAC
})(FloodChatApiContainer)
Why useEffect doesn't work? It seems to me like it should, but it doesnt.
I figured it out. Since I use data from static file, I need to implement functions that get/set data from/to local storage right where I import it which is container component. Once I put those useEffect functions in container component it works perfectly well.
const FloodChatApiContainer = (props) => {
useEffect(()=> {
props.setFloodMessages(data)
}, [])
useEffect(()=> {
let data = JSON.parse(localStorage.getItem('flood-messages'));
if(data){
props.setFloodMessages(data)
}
console.log('get')
}, [])
useEffect(() => {
localStorage.setItem('flood-messages', JSON.stringify(props.messages));
console.log('set')
}, [props.messages]);
return <FloodChat messages={props.messages}
setFloodMessages={props.setFloodMessages}
addFloodMessage={props.addFloodMessage}
deleteFloodMessage={props.deleteFloodMessage}
upadateMessage={props.upadateMessage}
/>
}
const mapStateToProps = (state) => ({
messages: state.flood.messages
})
export const FloodChatContainer = connect(mapStateToProps, {
setFloodMessages: setFloodMessagesAC,
addFloodMessage: addFloodMessageAC,
deleteFloodMessage: deleteFloodMessageAC,
upadateMessage: upadateMessageAC
})(FloodChatApiContainer)

reset new array reactjs infinite scroll

I have tried infinite scroll for reactjs from this link https://www.youtube.com/watch?v=NZKUirTtxcg&t=303 and work perfectly. But I want to improve with my condition.
I have make infite scroll for case products, the product has sub_category and sub_category has one category. For example I have one page showing all products by category (it's showing all sub_category).
The user can choose the product base sub_category (the page showing just what user choose for sub_category).
And my problem is I don't know to reset product variable as new array to fullfill products from sub_category.
I have two component ListInfiteTwo.jsx and UseProductSearch.jsx
ListInfiteTwo.jsx
import React, { useEffect, useState, useRef, useCallback } from 'react';
import axios from 'axios';
import { makeStyles } from '#material-ui/core/styles';
import Grid from '#material-ui/core/Grid';
import '../styleProduct.css';
import { NavbarPageListProduct, NotFoundPage, COBottomNav } from '../../../components';
import configAPI from '../../../api/configAPI';
import productAPI from '../../../api/productAPI';
import Kcard from '../../Card/Kcard';
import UseProductSearch from './UseProductSearch';
export default function ListInfiniteTwo(props) {
const classes = useStyles();
const [totQtyItem, setTotQtyItem] = useState(null);
const [pageNumber, setPageNumber] = useState(1);
const [category, setCategory] = useState(props.match.params.id);
const [subCategory, setSubCategory] = useState(null);
const [subCategories, setSubCategories] = useState([]);
const [amount, setAmount] = useState(0);
const [limit, setLimit] = useState(6);
const [selectedSubCategory, setSelectedSubCategory] = useState('selectedSubCategory');
const {
loading,
error,
products,
hasMore
} = UseProductSearch(pageNumber, category, limit, subCategory)
const observer = useRef()
const lastProductElementRef = useCallback(node => {
if (loading) return
if (observer.current) observer.current.disconnect()
observer.current = new IntersectionObserver(entries => {
if (entries[0].isIntersecting && hasMore) {
setPageNumber(prevPageNumber => prevPageNumber + 1)
}
})
if (node) observer.current.observe(node)
}, [loading, hasMore])
useEffect(() => {
let getSubCategoriesAct = configAPI.getSubCategory(kategori);
getSubCategoriesAct.then((response) => {
setSubCategories(response.data)
}).catch(error => {
console.log(error)
});
},[])
const callBackAddItemTotal = (data) => {
setTotQtyItem(data)
}
const callBackDeleteItemTotal = (data) => {
setTotQtyItem(data)
}
const callBackCalculateAmount = (data) => {
setAmount(data);
}
const selectSubCategory = (id) => {
setSubKategori(id)
setPageNumber(1)
}
return (
<>
<NavbarPageListProduct
titleView="List Product"
viewPrev="detailOrder"
totalQtyItem={totQtyItem}
cHistoryId={props.match.params.id}
/>
<div className={classes.root}>
<div className="css-ovr-auto">
<div className="css-ovr-auto">
<div className="css-c-1hj8">
<div className="css-c-2k3l">
{
<>
<div className={ selectedSubCategory === 'selectedSubCategory' ? 'css-sb-sl-top-active' : 'css-sb-sl-top'} >
<div className="css-sb-sl-label">
<span className="css-sb-sl-val"> All on Category </span>
</div>
</div>
{subCategories.map((x, z) =>
<div className="css-sb-sl-top" onClick={() => selectSubCategory(x._id) }>
<div className="css-sb-sl-label">
<span className="css-sb-sl-val" >{x.name}</span>
</div>
</div>
)}
</>
}
</div>
</div>
</div>
</div>
<Grid container spacing={1}>
<Grid container item xs={12} spacing={1}>
{
products.length >= 1 ?
products.map((pr, index) =>
<React.Fragment>
<div ref={lastProductElementRef}></div>
<Kcard
ref={lastProductElementRef}
product={pr}
callBackAddItemTotal={callBackAddItemTotal}
callBackDeleteItemTotal={callBackDeleteItemTotal}
callBackCalculateAmount={callBackCalculateAmount}
/>
</React.Fragment>
)
:
<NotFoundPage
content="No Products"
/>
}
</Grid>
</Grid>
</div>
<div>{loading && 'Loading...'}</div>
<div>{error && 'Error'}</div>
{
amount > 0 ?
<COBottomNav
titleBottom="Total Pay"
amount={amount}
titleBtnBottom="Process"
action='proces_list'
/>
:
""
}
</>
)
}
UseProductSearch.jsx
import { useEffect, useState } from 'react';
import axios from 'axios';
export default function UseProductSearch(pageNumber, category, limit, subCategory) {
const [loading, setLoading] = useState(true)
const [error, setError] = useState(false)
const [products, setProducts] = useState([])
const [hasMore, setHasMore] = useState(false)
const [lastPage, setLastPage] = useState(0)
useEffect(() => {
setProducts([])
}, [])
useEffect(() => {
setLoading(true)
setError(false)
let cancel
if (subCategory) {
setProducts([])
}
axios({
method: 'GET',
url: process.env.REACT_APP_API_URL + `data-product-pagination`,
params: {
orderby: 'newest',
type: 'verify',
page: pageNumber,
limit: limit,
xkategori: category,
subkategori: subCategory,
},
cancelToken: new axios.CancelToken(c => cancel = c)
}).then(res => {
if (res.data.data) {
if (res.data.data.data.length > 0) {
setProducts(prevProducts => {
return [...new Set([...prevProducts, ...res.data.data.data])]
})
}
}
setHasMore(res.data.data.data.length > 0)
setLoading(false)
setLastPage(res.data.data.last_page)
}).catch(e => {
if (axios.isCancel(e)) return
setError(true)
})
return () => cancel()
}, [pageNumber, category, limit, subCategory])
return { loading, error, products, hasMore }
}
what I have tried to add code on UseProductSearch.jsx
if (subCategory) {
setProducts([])
}
it's work when user choose sub category the page showing new products base on sub_category, but when I scroll down it's reseting the product to empty array.
Thx, for your help...
Try including subCategory as a dependency in your first useEffect hook from useProductSearch instead. This would reset your array whenever the subCategory state changes.
useEffect(() => {
setProducts([])
}, [subCategory])

Component not rerendering after axios Get (React)

I'm trying to render List of items of my DB using React.Context.
All my request work pretty well.
when i console log my states first I get an empty array and then array with the data that I need but my component is not updating. I have to go to another page an then go back to this page to get the data. I don't really understand why... here are my files..
ArticlesContext.js :
import React, { useState, createContext, useEffect } from 'react';
import axios from 'axios'
export const ArticlesContext = createContext();
export function ArticlesProvider(props) {
const [articles, setArticles] = useState([]);
const [user, setUser] =useState(0)
async function getArticles () {
await axios.get(`/api/publicItem`)
.then(res => {
setArticles(res.data);
})
}
useEffect( () => {
getArticles()
}, [user])
console.log(articles);
return (
<ArticlesContext.Provider value={[articles, setArticles]}>
{props.children}
</ArticlesContext.Provider>
);
}
Inventaire.js :
import React, { useContext, useEffect, useState } from 'react';
import './Inventaire.css';
import { ArticlesContext } from '../../../context/ArticlesContext';
import DeleteAlert from './Delete/Delete';
import Modify from './Modify/Modify';
import Filter from './Filter/Filter';
import axios from 'axios'
import Crud from '../../Elements/Articles/Crud/Crud';
import List from './List/List';
export default function Inventaire() {
const [articles, setArticles] = useContext(ArticlesContext);
const [filter, setFilter] = useState(articles)
console.log(articles);
//list for Inputs
const cat = articles.map(a => a.category.toLowerCase());
const categoryFilter = ([...new Set(cat)]);
const gender = articles.map(a => a.gender.toLowerCase());
const genderFilter = ([...new Set(gender)]);
//Event Listenner
//Uncheck All checkboxes
function UncheckAll() {
const el = document.querySelectorAll("input.checkboxFilter");
console.log(el);
for (var i = 0; i < el.length; i++) {
var check = el[i];
if (!check.disabled) {
check.checked = false;
}
}
}
//SearchBar
const searchChange = (e) => {
e.preventDefault();
const stuff = articles.filter((i) => {
return i.name.toLowerCase().match(e.target.value.toLowerCase())
})
setFilter(stuff)
UncheckAll(true)
}
const Types = (e) => {
if (e.target.checked === true) {
const stuff = filter.filter((i) => {
return i.category.toLowerCase().match(e.target.value.toLowerCase())
})
setFilter(stuff)
console.log(articles);
} else if (e.target.checked === false) {
setFilter(articles)
}
}
const Gender = (e) => {
if (e.target.checked === true) {
const stuff = filter.filter((i) => {
console.log(i.category, e.target.value);
return i.gender.toLowerCase().match(e.target.value.toLowerCase())
})
setFilter(stuff)
} else if (e.target.checked === false) {
setFilter(articles)
}
}
return (
<div className="inventaireContainer">
<input type="text" placeholder="Recherche un Article" onChange={searchChange} />
<div className="inventaireMenu">
<Crud />
<Filter
filter={Types}
categorys={categoryFilter}
genre={genderFilter}
target={Gender}
/>
</div>
<List filter={filter} articles={articles}/>
</div>
)
}
List.js :
import React from 'react';
import DeleteAlert from '../Delete/Delete';
import Modify from '../Modify/Modify';
export default function List({ filter, articles }) {
return (
<div>
{filter.map((details, i) => {
return (
<div className="inventaireBlock" >
<div className="inventaireGrid">
<div className="inventaireItemImg">
<img src={details.image} alt="ItemImg" />
</div>
<h2>{details.name}</h2>
<h3>{details.category}</h3>
<h3>{details.gender}</h3>
<div>
<p>S :{details.sizes[0].s}</p>
<p>M :{details.sizes[0].m}</p>
<p>L :{details.sizes[0].l}</p>
<p>XL :{details.sizes[0].xl}</p>
</div>
<h2> Prix: {details.price}</h2>
<div className="modify">
<Modify details={details._id} />
</div>
<div className="delete" >
<DeleteAlert details={details._id} articles={articles} />
</div>
</div>
</div>
)
})}
</div>
)
}
Thanks for your time

Resources