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
Related
So there is a storage containing 2 lists, one of the lists is fetching from server (using axios).
Both the lists renders by FC - PlayerList.
RondomizerPage contains these 2 lists.
So when I F5 my page on "localhost:3000/randomizer" nothing appears to be in my fetched list(fetched confirmed). But when I click anything(link to "randomizer" for example or any button) rerender goes in, and my list appears.
The 'store':
import { makeAutoObservable } from "mobx";
import { IPlayerInfo } from "../types/player";
import axios from "../axios";
import IMove from "./../types/movement";
class Player {
playerList: IPlayerInfo[] = [];
randomPlayerList: IPlayerInfo[] = [];
isAuth: boolean = false;
constructor() {
makeAutoObservable(this);
}
addPlayer(playerdata: IPlayerInfo) {
this.playerList.push(playerdata);
}
move(from: IMove, to: IMove) {
if (from.list === to.list) {
const list = from.list;
if (list === "randomList") {
const [temp] = this.randomPlayerList.splice(from.index, 1);
this.randomPlayerList.splice(to.index, 0, temp);
}
if (list === "playerList") {
const [temp] = this.playerList.splice(from.index, 1);
this.playerList.splice(to.index, 0, temp);
}
} else {
if (from.list === "playerList") {
const [temp] = this.playerList.splice(from.index, 1);
this.randomPlayerList.splice(to.index, 0, temp);
}
if (from.list === "randomList") {
const [temp] = this.randomPlayerList.splice(from.index, 1);
this.playerList.splice(to.index, 0, temp);
}
}
}
fetchPlayers = async () => {
try {
const response = await axios.get("/players");
this.playerList = response.data;
return
} catch (error) {
console.log(error);
}
};
randomPlayers = async () => {
if (
this.randomPlayerList.length % 2 === 0 &&
this.randomPlayerList.length > 1
) {
const response = await axios.post("/random", {
amount: this.randomPlayerList.length,
});
const data = response.data.result.random.data[0];
let playerList = [];
for (let index = 0; index < data.length; index++) {
playerList.push(this.randomPlayerList[data[index] - 1]);
}
return playerList;
}
return false;
};
}
const playerStore = new Player()
export default playerStore;
And I have a 'Randomizer page':
import React, { useEffect, useState } from "react";
import PlayerList from "../../components/Lists/PlayerList";
import players from "../../store/players";
import styles from "./RandomizerPage.module.scss";
import { useNavigate } from "react-router";
import axios from "../../axios";
import { DragDropContext, Droppable, DropResult } from "react-beautiful-dnd";
import IMove from "./../../types/movement";
import PlayerCreation from "../../components/Modals/PlayerCreationModal/PlayerCreation";
import MyButton from "../../components/UI/MyButton/MyButton";
import RandomedPlayersModal from "../../components/Modals/RandomedPlayersModal/RandomedPlayersModal";
import { observer } from "mobx-react-lite";
const RandomizerPage = observer(() => {
const [playerCreationModalisOn, setPlayerCreationModalisOn] =
useState(false);
const [randomedPlayerModalIsOn, setRandomedPlayerModalIsOn] =
useState(false);
const nav = useNavigate();
const onDragEndHandle = (result: DropResult) => {
if (!result.destination) return;
const from: IMove = {
index: result.source.index,
list: result.source.droppableId,
};
const to: IMove = {
index: result.destination.index,
list: result.destination.droppableId,
};
players.move(from, to);
};
const playerCreationHandler = () => {
setPlayerCreationModalisOn(true);
};
const playerCreationAbortion = () => {
setPlayerCreationModalisOn(false);
};
const randomPlayersHandler = () => {
const response = players.randomPlayers();
console.log(response);
setRandomedPlayerModalIsOn(true);
};
const randomPlayerAbortion = () => {
setRandomedPlayerModalIsOn(false);
};
useEffect(() => {
const user = JSON.parse(localStorage.getItem("user") || "null");
if (user) {
axios.defaults.headers["authorization"] = user.token;
players.fetchPlayers();
} else nav("/login");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<>
{playerCreationModalisOn && (
<PlayerCreation
abort={playerCreationAbortion}
title={"Создание персонажа"}
/>
)}
{randomedPlayerModalIsOn && (
<RandomedPlayersModal
abort={randomPlayerAbortion}
title={"random.org выбрал команды"}
/>
)}
<DragDropContext onDragEnd={onDragEndHandle}>
<div className={styles.wrapper}>
<div className={styles.column}>
<div>
<h4>Переместите сюда игроков</h4>
<Droppable droppableId="randomList">
{(provided) => (
<div
className={styles.list}
{...provided.droppableProps}
ref={provided.innerRef}
>
<PlayerList list={players.randomPlayerList} />
{provided.placeholder}
</div>
)}
</Droppable>
</div>
<MyButton click={randomPlayersHandler}>
Сгенерировать случайные команды
</MyButton>
</div>
<div className={styles.column}>
<div>
<h4>Игроки</h4>
<Droppable droppableId="playerList">
{(provided) => (
<div
className={styles.list}
{...provided.droppableProps}
ref={provided.innerRef}
>
<PlayerList list={players.playerList} />
{provided.placeholder}
</div>
)}
</Droppable>
</div>
<MyButton click={playerCreationHandler}>
Добавить игрока
</MyButton>
</div>
</div>
</DragDropContext>
</>
);
});
export default RandomizerPage;
And my PlayerList looks like that, btw:
import React from "react";
import { observer } from "mobx-react-lite";
import { Draggable } from "react-beautiful-dnd";
import PlayerCard from "../PlayerCard/PlayerCard";
import { IPlayerInfo } from "../../types/player";
interface PlayerListProps {
list: IPlayerInfo[];
}
const PlayerList = observer(({ list }: PlayerListProps) => {
console.log('rerender', list);
return (
<>
{list.map((player: IPlayerInfo, index: number) => (
<Draggable
key={player.steamId}
draggableId={player.steamId}
index={index}
>
{(provided) => (
<PlayerCard
playerinfo={player}
{...provided.draggableProps}
{...provided.dragHandleProps}
innerRef={provided.innerRef}
/>
)}
</Draggable>
))}
</>
);
});
export default PlayerList;
So, I found the crutch, if I add in RandomizerPage and change list={playerList}:
const playerList = players.playerList
I am trying to implement a search parameter functionality to my React image search app. And, I have learned that I need to (can) use the useSearchParams Hook, but I am not sure how to make these changes.
So, basically I want the URL to be something like localhost:3000/input&page=1, meaning that whatever comes after the slash is going to be the input value and key/value pair for page numbers.
As you can see in the app.js, I have these 3 main Routes and the Home Route (renders Main.js) is the one I am mainly working on. Also, Main.js renders Header.js (renders form and others).
I am thinking that I should create a new Route in the app.js but I am not sure what to do.
import './App.css';
import Home from './components/pages/Home';
import Favorites from './components/pages/Favorites';
import Error from './components/pages/Error';
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { SkeletonTheme } from 'react-loading-skeleton';
import { useDarkMode } from './components/Navbar';
function App() {
const darkMode = useDarkMode(state => state.darkMode)
let style
if (darkMode === 'light') {
style = 'wrapper'
} else {
style = 'wrapper-dark'
}
return (
<div className={style}>
<SkeletonTheme baseColor="#808080" highlightColor="#b1b1b1">
<BrowserRouter>
<Routes>
<Route path='/' element={<Home />} />
<Route path='favorites' element={<Favorites />} />
<Route path='*' element={<Error />} />
</Routes>
</BrowserRouter>
</SkeletonTheme>
</div>
);
}
export default App;
import React from 'react'
import Header from './Header'
import Image from './Image'
import { useState, useEffect, useRef } from 'react'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faTriangleExclamation } from '#fortawesome/free-solid-svg-icons'
// import InfiniteScroll from 'react-infinite-scroll-component'
function Main() {
const [input, setInput] = useState('')
const [allImages, setAllImages] = useState([])
// const [totalResults, setTotalResults] = useState(null)
const [isVisible, setIsVisible] = useState(false)
const [error, setError] = useState(null)
const [showError, setShowError] = useState(false)
const [fadeOut, setFadeOut] = useState(false)
const [page, setPage] = useState(1)
const paginationRef = useRef(false)
// get
useEffect(() => {
if (localStorage.getItem('input')) {
setInput(JSON.parse(localStorage.getItem('input')))
}
if (localStorage.getItem('allImages')) {
setAllImages(JSON.parse(localStorage.getItem('allImages')))
// setTotalResults(JSON.parse(localStorage.getItem('totalResults')))
setIsVisible(JSON.parse(localStorage.getItem('isVisible')))
setPage(JSON.parse(localStorage.getItem('page')))
paginationRef.current = true
}
}, [])
// set
//* dryer?
useEffect(() => {
localStorage.setItem('input', JSON.stringify(input))
}, [input])
useEffect(() => {
localStorage.setItem('allImages', JSON.stringify(allImages))
}, [allImages])
// useEffect(() => {
// localStorage.setItem('totalResults', JSON.stringify(totalResults))
// }, [totalResults])
useEffect(() => {
localStorage.setItem('isVisible', JSON.stringify(isVisible))
}, [isVisible])
function handleChange(event) {
setInput(event.target.value)
}
// display nothing by default
// display image-list when user press search button
// function handleSubmit(event) {
// event.preventDefault()
// // interpolate input state and .env variable to API
// fetch(`https://api.unsplash.com/search/photos?query=${input}&client_id=${process.env.REACT_APP_UNSPLASH_API_KEY}`)
// .then(res => res.json())
// .then(data => setAllImages(data.results))
// }
async function fetchImages() {
try {
const res = await fetch(`https://api.unsplash.com/search/photos?&page=${page}&per_page=30&query=${input}&client_id=${process.env.REACT_APP_UNSPLASH_API_KEY}`)
const data = await res.json()
if (data.total !== 0) {
setAllImages(data.results)
// setTotalResults(data.total)
setIsVisible(true)
}
} catch(error) {
setError(error)
}
}
const handleSubmit = async (event) => {
event.preventDefault();
fetchImages()
setPage(1)
paginationRef.current = true
}
// error
useEffect(() => {
if (error) {
setShowError(true)
setTimeout(() => {
setFadeOut(true)
setTimeout(() => {
setShowError(false)
}, 1000)
}, 5000)
}
}, [error])
// total results
// let results
// if (totalResults >= 10000) {
// results = 'Total Results: ' + totalResults + '+'
// } else if (totalResults > 0) {
// results = 'Total Results: ' + totalResults
// } else if (totalResults === 0) {
// results = 'Nothing Found'
// }
// pagination
useEffect(() => {
if (paginationRef.current) {
fetchImages()
}
localStorage.setItem('page', JSON.stringify(page))
}, [page])
function handlePrev() {
setPage(prevState => prevState - 1)
fetchImages()
}
function handleNext() {
setPage(prevState => prevState + 1)
fetchImages()
}
return (
<main>
<Header
input={input}
handleChange={handleChange}
handleSubmit={handleSubmit}
/>
{showError && <div className={`network-error ${fadeOut ? 'fade-out' : ''}`}>
<i><FontAwesomeIcon icon={faTriangleExclamation} /></i>
<div className='network-error--message'>
<h5>Network Error</h5>
<p>Please check your Internet connection and try again</p>
</div>
</div>}
{/* <p className='main--results'>{results}</p> */}
<div className='main--image-list mt-5 pb-5'>
{allImages.map(el => (
<Image
key={el.id}
// do need spread operator below for img's src to work in Image.js
{...el}
el={el}
/>
))}
</div>
{isVisible && <div className='main--pagination'>
<button disabled={page === 1} onClick={handlePrev}>
Prev
</button>
<h5 className='main--pagination--h5'>{page}</h5>
<button onClick={handleNext}>
Next
</button>
</div>}
</main>
)
}
export default Main
import React from 'react'
import Navbar from './Navbar'
function Header(props) {
return (
<div className='header'>
<Navbar />
<h2 className='header--heading text-center text-light'>Find Images</h2>
<div className='header--form'>
<form onSubmit={props.handleSubmit}>
<input
className='header--form--input'
autoComplete='off'
type='text'
placeholder='Search'
onChange={props.handleChange}
name='input'
value={props.input}
/>
</form>
</div>
</div>
)
}
export default Header
If you are just wanting to initialize the page state to the page queryParam the the following could work. If uses the useSearchParams to access the queryString and return a constructed URLSearchParams object which can then access individual query params. Pass the "page" query param as the initial page state value.
const [searchParams] = useSearchParams();
const [page, setPage] = useState(Number(searchParams.get("page")) || 1);
In all likelihood though you'll not want competing "sources of truth" for what the current page is. If you want the URL queryString to be the source of truth then remove the page state and just read/update the "page` query parameter directly.
Example:
function Main() {
const [searchParams, setSearchParams] = useSearchParams();
...
const page = Number(searchParams.get("page"));
// get
useEffect(() => {
...
if (localStorage.getItem('allImages')) {
...
setSearchParams(params => {
params.set("page", JSON.parse(localStorage.getItem('page')) || 1);
return params;
});
...
}
}, []);
...
const handleSubmit = async (event) => {
event.preventDefault();
...
setSearchParams(params => {
params.set("page", 1);
return params;
});
...
}
...
// pagination
useEffect(() => {
if (paginationRef.current) {
fetchImages();
}
localStorage.setItem('page', JSON.stringify(page));
}, [page])
function handlePrev() {
setSearchParams(params => {
params.set("page", Math.max(1, page - 1));
return params;
});
...
}
function handleNext() {
setSearchParams(params => {
params.set("page", page + 1);
return params;
});
...
}
return (
...
);
}
So I am trying to set a searchbar that has a drop down menu that gives you options on what you want to search for=and then let the user input. I have a list of inspections that I want to base that on.
For example I want to search inspections that only have issues with pests, so the user selects the pest option for search and then inputs-hive beetles
so the dropdown should have an option of searching by: pests, notes, actions taken, and so forth, my table has 8 values that I want to specific each search.
I have am using React for this and my database is in django, any suggestions on how to tackle this? The research I found is not really helpful.
My InpsectionSearch
import {React, useState} from "react";
const SearchInspections = (inspections) => {
const [searchField, setSearchField] = useState("")
const [searchResults, setSearchResults] = useState([])
function handleChange(event){
event.preventDefault()
const filteredInspections = inspections.filter((inspections) => {
return (
inspections.eggs().includes(searchField.toLowerCase()) ||
inspections.larvae().includes(searchField.toLowerCase()) ||
inspections.sealed_brood().includes(searchField.toLowerCase()) ||
inspections.covered_bees().includes(searchField.toLowerCase()) ||
inspections.nectar_honey().includes(searchField.toLowerCase()) ||
inspections.pollen().includes(searchField.toLowerCase()) ||
inspections.pest_spotted.toLowerCase().includes(searchField.toLowerCase()) ||
inspections.pest_action.toLowerCase().includes(searchField.toLowerCase()) ||
inspections.notes_concerns.toLowerCase().includes(searchField.toLowerCase())
)
})
setSearchResults(filteredInspections)
if(searchField.length > 0){
inspections(searchResults)
}
}
return (
<form onSubmit={handleChange}>
<h3>Search For Your Item</h3>
<input type="search" placeholder='Search Song' value={searchField} onChange={event => setSearchField(event.target.value)}/>
<button type='submit'>Click twice to search</button>
</form>
);
}
export default SearchInspections;
my Inspection Page where the searchbar will be
import { React, useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import axios from "axios";
import useAuth from "../../hooks/useAuth";
import DisplayInspections from "../../components/DisplayInspections/DisplayInspections";
import InspectionTracker from "../../components/InspectionTracker/InspectionTracker";
import SearchInspections from "../../components/InspectionSearch/InspectionSearch"
const InspectionPage = (props) => {
const [user, token] = useAuth();
const [inspections, setInspections] = useState([]);
const { id } = useParams();
useEffect(() => {
fetchInspections();
}, [token]);
const fetchInspections = async () => {
try {
let response = await axios.get(
`http://127.0.0.1:8000/api/inspections/all/${id}`,
{
headers: {
Authorization: "Bearer " + token,
},
}
);
setInspections(response.data);
} catch (error) {
console.log(error.response.data);
}
};
function applyFilter(category, userInput){
if(category === 'All' || userInput ===''){
console.log('working!')
fetchInspections();
}
else
{
let newInspections = inspections.filter(function(element){
if(element[category] === userInput){
return true;
}
})
setInspections(newInspections);
}
}
return (
<div className="container">
<InspectionTracker inspections={inspections} />
<SearchInspections inspections={inspections} />
<DisplayInspections
inspections={inspections}
setSelectedHive={props.setSelectedHive}
setSelectedInspection={props.setSelectedInspection}
/>
</div>
);
};
export default InspectionPage;
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"
There is some issues with state in Redux. I want to change color of a component with state update. But the state in TargetList.js has error: TypeError: Cannot read property 'includes' of undefined.
The Reducer file is:
import {
SENSOR_HI,
SENSOR_UNHI,
} from "redux/actionTypes";
const initialState = {
title: "",
text: "",
detailedList: "hide",
};
const Reducer = (state = initialState, action) => {
switch (action.type) {
case SENSOR_HI:
return {
...state,
sensorarray: action.data,
};
case SENSOR_UNHI:
return {
...state,
sensorarray: [],
};
case FILTER_TAGS_CHANGED:
return {
...state,
filterTags: action.data,
};
default:
return state;
}
};
export default Reducer;
And the TargetList.js is:
import "assets/scss/global.scss";
import moment from "jalali-moment";
import React, { useState, useEffect, useRef, memo } from "react";
import { OverlayTrigger, Tooltip } from "react-bootstrap";
import { GiMovementSensor, GiRadarSweep } from "react-icons/gi";
import { MdDescription, MdSignalWifiOff,MdNetworkWifi } from "react-icons/md";
import { connect } from "react-redux";
import ToggleButton from "react-switch";
import socketConn from "sockets";
import "./Leaflet.scss";
import classes from "./TargetsList.module.scss";
import { targetTypes, targetsIconsHandlerImage } from "helpers/icons";
import { BackButton } from "assets/js/Icons";
import ReactDOMServer from "react-dom/server";
let TEMP_TARGETS = [];
let counter = 0;
let now = new Date();
const TargetsList = memo((props) => {
const [sensorFiltersSelected, setSensorFiltersSelected] = useState([]);
const [sensorFiltersSelectedIds, setSensorFiltersSelectedIds] = useState([]);
const [sensorSelected, setSensorSelected] = useState(null);
const [targetFiltersSelected, setTargetFiltersSelected] = useState([]);
const [hi, sethi] = useState(false);
let filterType = (sensors) => {
if (sensorFiltersSelected.length == 0) {
return sensors;
} else {
let ids = sensorFiltersSelected.map((s) => s["_id"]);
return sensors.filter((s) => ids.includes(s.sensorType["_id"]));
}
};
let filterTextSensors = (sensors) => {
return sensors.filter((s) => s.latinName.includes(searchInput));
};
let toggleFilter = (sensor) => {
let filters = sensorFiltersSelected;
let ids = filters.map((f) => f["_id"]);
if (filters.length && ids.includes(sensor["_id"])) {
filters = filters.filter((f) => f["_id"] != sensor["_id"]);
} else {
filters.push(sensor);
}
props.dispatch({
type: "FILTER_TAGS_CHANGED",
data: [...filters],
});
setSensorFiltersSelected(filters);
setSensorFiltersSelectedIds(filters.map(s=>s.latinName))
props.dispatch({
type: "SENSOR_HI",
data: [filters.map(s=>s.latinName)],
});
};
return (
<div>
<div
className="container"
style={{
padding: 0,
}}
>
<div className="rowx my-2 flex-wrap">
{props.sensors && props.sensors.length
? filterTextSensors(props.sensors).map(
(s, sensorTypeIndex) => (
<div
key={s._id}
/////////////////////////////////////// Here is Error ///////////////////////////////////////////////
className={`cursor-pointer badge badge-pill m-1 ${props.sensorarray.includes(s.latinName) ? `badge-success` : `badge-light`}`}
onClick={() => {
showLogsSensor(s)
toggleFilter(s);
}}
>
{s.persianName}
</div>
)
)
: ""}
</div>
});
const mapStateToProps = (state) => {
return {
sensorarray: state.sensorarray,
};
};
export default connect(mapStateToProps)(TargetsList);
And the Drawer.js is change state that should color change in TargetList.js.
Drawer.js:
import React from "react";
import clsx from "clsx";
import {makeStyles} from "#material-ui/core/styles";
import Drawer from "#material-ui/core/Drawer";
import {connect} from "react-redux";
import "assets/scss/global.scss";
import "./style.scss";
import socketConn from "sockets";
import moment from "jalali-moment";
import {MdSave} from "react-icons/md";
import axios from "config.js";
const useStyles = makeStyles({
fullList: {
width: "auto",
},
});
function BottomDrawer(props) {
const classes = useStyles();
const [tab, setTab] = React.useState("sensors");
const [state, setState] = React.useState({bottom: false});
const [type, setType] = React.useState(null);
const [info, setInfo] = React.useState(null);
const [logs, setLogs] = React.useState([]);
const toggleDrawer = (anchor, open) => {
setState({
...state,
[anchor]: open,
});
// stop receiving target logs
targetsLogAPIHandler(false);
};
const sensorunhi = () => {
props.dispatch({
type: "SENSOR_UNHI",
});
};
let setLogSocket = (type, info) => {
setLogs([]);
if (type === "target") {
targetsLogAPIHandler(true, info);
}
if (type === "sensor") {
sensorsLogAPIHandler(info);
}
};
// handler for API request to NodeJS to get logs of specific target (! ! ! requestMode => {true: when you want to START coming logs | false: when you want to STOP coming logs})
const targetsLogAPIHandler = async (requestMode, info) => {
try {
const userId = localStorage.getItem('user_id');
socketConn().removeAllListeners("show_specific_target_log");
const {data} = await axios.post(`/targets/log/${userId}`, {
requestMode,
unique_id: info ? info.unique_id : undefined
});
socketConn().on("show_specific_target_log", targetLogs => {
setLogs((prev) => {
return [targetLogs, ...prev].filter((s, index) => index < 500);
});
});
} catch (err) {
console.log(err);
}
};
// handler for API request to NodeJS to get logs of specific sensor
const sensorsLogAPIHandler = async info => {
try {
socketConn().removeAllListeners("sensor_moment_log");
let userId = localStorage.getItem("user_id");
const logs = await axios.post(`sensors/sensors/logs`, {topic: info.latinName, userId});
socketConn().on("sensor_moment_log", (data) => {
let enc = new TextDecoder("utf-8");
let decoded = enc.decode(data.result.content);
decoded = JSON.parse(decoded);
setLogs((prev) => {
return [decoded, ...prev].filter((s, index) => index < 500);
});
});
socketConn().on("sensor_moment_log_error", (data) => {
console.log(data);
});
} catch (err) {
console.log(err);
}
};
React.useEffect(() => {
setTab((prev) => {
if (prev != props.selectedTab) {
socketConn().removeAllListeners("sensor_moment_log");
socketConn().removeAllListeners("show_specific_target_log");
setLogs([]);
return props.selectedTab;
}
return prev;
});
}, [props.selectedTab]);
React.useEffect(() => {
if (props.showLogs && state["bottom"] == false) {
toggleDrawer("bottom", true);
}
}, [props.showLogs]);
React.useEffect(() => {
if (props.logInfo && props.logType) {
if (info != null) {
if (
type != props.logType ||
info.Identification + info.sensorName !=
props.logInfo.Identification + props.logInfo.sensorName
) {
setType(props.logType);
setInfo(props.logInfo);
setLogSocket(props.logType, props.logInfo);
}
} else {
setType(props.logType);
setInfo(props.logInfo);
setLogSocket(props.logType, props.logInfo);
}
}
}, [props.logInfo, props.logType]);
const list = anchor => (
<div className={clsx(classes.list, {[classes.fullList]: anchor === "bottom",})} role="presentation">
<div className="log-container p-4">
<React.Fragment>
<div className="rowx log-headers mb-3">
<div className="colx log-header font-weight-bold">نام سنسور</div>
<div className="colx log-header font-weight-bold">نوع هدف</div>
<div className="colx log-header font-weight-bold">طول</div>
<div className="colx log-header font-weight-bold">عرض</div>
<div className="colx log-header font-weight-bold">ارتفاع</div>
</div>
<div className="log-elements">
{logs &&
logs.length &&
logs.map((log, index) => (
<div className="rowx log-element mb-2" key={index}>
<div className="colx log-text">{log && log[0] && log[0].sensorName}</div>
<div className="colx log-text">{log && log[0] && log[0].sensorType}</div>
<div className="colx log-text">{log && log[0] && log[0].longitude}</div>
<div className="colx log-text">{log && log[0] && log[0].latitude}</div>
<div className="colx log-text">{log && log[0] && log[0].altitude}</div>
</div>
))}
</div>
</React.Fragment>
)}
</div>
</div>
);
return (
<div>
<React.Fragment>
<Drawer
classes={{root: "drawer-root"}}
ModalProps={{hideBackdrop: true}}
anchor="bottom"
open={state["bottom"]}
onClose={() => {
toggleDrawer("bottom", false);
sensorunhi(); /////////////////// CHANGE REDUX STATE
}}
>
{list("bottom")}
</Drawer>
</React.Fragment>
</div>
);
}
const mapStateToProps = (state) => {
return {
sensorarray: state.sensorarray,
};
};
export default connect(mapStateToProps)(BottomDrawer);
In other word, I want to change the color component TargetList.js by change the state in Drawer.js.