React JS coponent not rendering using map function - reactjs

I hava a component called videoRow i try to render this component using dummy values now i get data from a useEffect Hook i have to use that data to render my component but when i try to do so it dont show anything. I even try console log to check weather i get my data or not it print my data on console means my useEffect is working But when i try this data on my videoRow component it not show anything
import React, { useState, useEffect } from "react";
import "../css/searchPage.css";
import TuneSharpIcon from "#mui/icons-material/TuneSharp";
import ChannelRow from "./ChannelRow";
import VideoRow from "./VideoRow";
import { selectInput } from "../features/inputSlice";
import { useSelector } from "react-redux";
import Axios from "axios";
function SearchPage() {
const getQuery = useSelector(selectInput);
const API_URL = `https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=4&key=APIKEY&type=video&q=${getQuery.input}`;
const [data, setData] = useState([]);
useEffect(() => {
async function fetchData() {
let request = await Axios.get(API_URL);
setData(request);
}
fetchData();
}, [API_URL]);
console.log(data);
return (
<div className="searchPage">
<div className="filter">
<TuneSharpIcon></TuneSharpIcon>
<h2>FILTERS</h2>
</div>
<hr></hr>
<ChannelRow
image="https://images.indianexpress.com/2022/01/Republic-Day_1200_AP2022.jpg"
channelName="Dummy"
verified
subs="670k"
noOfVideos={567}
desc="You can find awesome programming lessons here! Also, expect programming tips and tricks that will take your coding skills to the ..."
></ChannelRow>
<hr></hr>
{data?.data?.items?.forEach((item) => {
console.log(item.snippet.title);
console.log(item?.snippet.thumbnails.high.url)
console.log(item?.snippet.publishedAt)
console.log(item?.snippet.description)
console.log(item?.snippet.channelTitle)
return(<VideoRow
image={item?.snippet.thumbnails.high.url}
channelName={item?.channelTitle}
timestamp={item?.snippet.publishedAt}
title={item?.snippet.title}
desc={item?.snippet.description}
views="1.4M"
subs="1.4M"
></VideoRow>)
})}
</div>
);
}
export default SearchPage;

Change data?.data?.items?.forEach to data?.data?.items?.map. forEach returns nothing. So, even if you return the component from the callback, forEach will just ignore it. But, map will return all transformed results as an array.
You can read more about lists in react here.

Related

Not able to Display API Data in react js

Guys I'm attempting to develop a modest film-based project. I have used TMDB Movies to obtain movies. I don't sure where I went wrong because the data in my console is displaying OK, but when I try to map and display that element, I receive an error saying "Movies.map is not a function." Please try to correct my mistake.
Thanks a lot!
enter image description here
`
import "./App.css";
import MemsData from "./Components/MemsData";
import NewMemsData from "./Components/NewMemsData";
import FilterElement from "./Components/FilterElement";
import MovieBox from "./Components/MovieBox";
import { useEffect, useState } from "react";
import Axios from "axios";
function App() {
const API_URL =
"https://api.themoviedb.org/3/movie/popular?api_key=8f11538792fbc26efa63aa919f0844b8";
const [movie, setMovie] = useState([]);
useEffect(() => {
Axios.get(API_URL).then((res) => {
console.log(res);
setMovie(res.data);
});
});
return (
<div className="App">
<h2>Movie Api</h2>
{
movie.map((moviereq, index) => {
return <div key={index}>{moviereq.title}</div>;
})}
</div>
);
}
export default App;
`
You need to go one deeper and access results: setMovie(res.data.results);
Codesandbox link: https://codesandbox.io/s/frosty-voice-hc912d?file=/src/App.js:392-400

Cannot update a component (`TodoForm`) while rendering a different component (`TodoTask`). [SOLUTION] [React Redux To-Do App]

WHILE WRITING THIS POST I REALIZED WHAT THE SOLUTION WAS
Every time I dispatch a task to my store the following error occurs:
I have some idea of why it happens. It happens precisely when I try to get the to-do list using useSelector and then mapping through the list. However, the mapping is not the issue but rather returning a react component on the map function. It works just fine if I do not return a functional component and instead use HTML. So the issue, from my POV, is returning a react functional component while passing props to it on a map function.
Here's the code for my home component:
import Input from '../components/Input';
import TodoForm from '../components/TodoForm';
function Home() {
document.title = "MyTodo | Home"
return (
<div className="App">
<h1>MyTodo</h1>
<Input />
<TodoForm />
</div>
);
}
export default Home;
The input component where the action is being dispatched on key down:
import {useState} from 'react'
import { useDispatch } from 'react-redux';
import { todoActions } from '../store/todo';
const Input = () => {
const [inputText, setInputText] = useState("");
const dispatch = useDispatch();
const handleChange = (e) => setInputText(e.target.value)
const handleKeyPress = (event) => {
if (event.code === "Enter") {
// if the expression is false, that means the string has a length of 0 after stripping white spaces
const onlyWhiteSpaces = !inputText.replace(/\s/g, "").length;
!onlyWhiteSpaces &&
dispatch(
todoActions.addTask({ label: inputText, done: false })
);
setInputText("");
}
};
return (
<input
type="text"
onKeyDown={(e) => handleKeyPress(e)}
onChange={(e) => handleChange(e)}
value={inputText}
/>
);
}
export default Input
The TodoForm where I am using useSelector to get the todo list from the redux store and mapping thru it:
import { useSelector } from "react-redux";
import { v4 as uuidv4 } from "uuid";
import TodoTask from "./TodoTask";
const TodoForm = () => {
const tasks = useSelector((state) => state.todo.taskList);
const renderedListItems = tasks.map((task, index) => {
return (
<TodoTask
key={uuidv4()}
task={task}
targetIndex={index}
/>
);
});
return <div className="container">{renderedListItems}</div>;
};
export default TodoForm;
Finally the TodoTask component which is the child component being returned on the map function above:
import { useDispatch } from "react-redux";
import { todoActions } from "../store/todo";
const TodoTask = ({ task, targetIndex }) => {
const {text, done} = task;
console.log("Task: ", task);
const dispatch = useDispatch()
const removeTask = dispatch(todoActions.deleteTask(targetIndex))
return (
<div
className="alert alert-primary d-flex justify-content-between"
role="alert"
>
{text}
<button type="button" className="btn-close" onClick={()=>removeTask}></button>
</div>
);
};
export default TodoTask;
This is my first time facing this issue, and I know it has something to do with redux and how the useSelector hook forces a component to re-render. So the useSelector is re-rendering the TodoForm component, and since we are mapping and returning another component, that component is also being rendered simultaneously. At least, that is how I understand it. Let me know if I am wrong.
Things I have tried:
Wrapping the TodoTask in React.memo. Saw it somewhere as a possible solution to this kind of issue, but that did not work.
Passing shallowEqual as a second parameter on the TodoForm useSelector. This does prevent the page from going into an infinity loop, but the tasks show up empty but are being added to the redux store. However, with this method, the first warning stills shows up, and the console log in the TodoTask component does not execute.
Passing shallowEqual as a second parameter on the TodoForm useSelector. This does prevent the page from going into an infinity loop but the tasks show up empty but are being added to the redux store. However, with this method, the first warning stills shows up and the console log in the TodoTask component does not execute.
I realized what I was doing wrong while writing this part. The console log in the TodoTask component was working, but I had the browser console filtering for errors only. When I check the messages section, I saw everything working fine. Then when I checked the Task component, I noticed I was trying to read a property that did not exist and hence why the tasks had no text.
In other words, the solution was adding shallowEqual as second parameter of the useSelector hook in my TodoForm component that was the one mapping thru the todo tasks array. As I said, useSelector forces a component to re-render. shallowEquals checks if the existing state isn't the same as we already had and avoids unnecessary re-renders, which can lead my application to exceed the maximum update length.
Code fix [Solution]:
import { memo } from "react";
import { shallowEqual, useSelector } from "react-redux";
import { v4 as uuidv4 } from "uuid";
import TodoTask from "./TodoTask";
const TodoForm = () => {
// shallowEqual prevents unnecessary re-renders which can lead to an infinite loop
// it compares the current state with the previous one, if they are the same, it does not re-render the component
const tasks = useSelector((state) => state.todo.taskList, shallowEqual);
const renderedListItems = tasks.map((task, index) => {
return (
<TodoTask
key={uuidv4()}
task={task}
targetIndex={index}
/>
);
});
return <div className="container">{renderedListItems}</div>;
};
export default memo(TodoForm);
Honestly, I have been stuck on this since yesterday and I cannot believe I realize the solution just when I was about to ask for help. Hope this helps anyone else who faces a similar issue in the future.

useSWR mutate function not working as expected

mutate function not working as i expected, when sharing same state with other components
expect:
every mutate call by clicking button, re-fetch original data, so i can find new post.json request on networkTab
working: but, every mutate call, not fetch new data. i couldn't find post.json on networkTab
if i remove Item.js file, it works as i expected.(every mutate-call, every re-fetch)
why this happening?
//App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
import useSWR from 'swr'
import ItemList from './ItemList';
function App() {
React.useEffect(()=>{
console.log('rerender')
})
const fetcher = async(urlKey) => {
const url = 'https://jsonplaceholder.typicode.com/posts';
const response = await fetch(url);
const result = await response.json();
return result
}
const {data,error,mutate} = useSWR('/get/posts',fetcher);
const updateFetch = () => {
mutate({},true);
}
return (
<div className="App">
<ItemList/>
<button onClick={updateFetch}>reFresh</button>
</div>
);
}
export default App;
//ItemList.js
import React from 'react'
import useSWR from 'swr';
function ItemList() {
const {data,error} = useSWR('/get/posts');
return null
}
export default ItemList
According to docs:
broadcast a revalidation message globally to other SWR hooks using the same key by calling mutate(key).
i.e You have to tell mutate which Api data you have to fetch again in your case. It would be like this:
mutate('/get/posts',true)
I have created this sandbox for reference: https://codesandbox.io/embed/reverent-cloud-fhm2w

Why my useState from Context doesn't update

Hello I try to save the fatched data from my database to my variable selectedRestaurant. I use setSelectedrestaurant in the useEffekt hook but it doesn't update my variable. I get as a value null.
Here is my code
import React, { useContext, useEffect, useState } from 'react';
import { useParams } from 'react-router';
import RestaurantFinder from '../api/RestaurantFinder';
import { RestaurantsContext } from "../context/RestaurantsContext";
import Reviews from '../components/Reviews';
import StarComponent from '../components/StarComponent';
import AddReview from '../components/AddReview';
import Test from '../components/Test';
const RestaurantDetailedPage = (props) =>{
//const{ selectedRestaurant, setSelectedRestaurant}= createContext(RestaurantsContext);
const[ selectedRestaurant, setSelectedRestaurant]= useState(null);
const {id} = useParams();
useEffect(()=>{
const fetchData = async(id)=>{
const result = await RestaurantFinder.get("/"+id);
console.log(result);
setSelectedRestaurant(result.data.data);
console.log(selectedRestaurant);
}
fetchData(id);
},[]);//Wichtig, damit es nur 1x
/*
useEffect(()=>{
console.log("useEffect2");
console.log(selectedRestaurant);
},[selectedRestaurant]);
*/
return(
<div>{selectedRestaurant && (
<>
<div>{<AddReview/>}</div>
<div></div>
</>
)}
</div>
)
}
export default RestaurantDetailedPage;
I know that useEffect is async so I tried with await setSelectedRestaurant(result.data.data)
but it didn't work. I also defined two useEffects that should invoke only once. One for changing and the other for update but both useEffects are invoked twice. I dont know why and how to solve it.
Hope u can help me
Try tidying up your sample code. There are lot of poorly formatter comments and spelling errors that make it difficult to parse.
EDIT:
When you update the state (i.e. setSelectedRestraunt) those changes are batched together don't change the state variable until the next render loop.
If you want to console.log or otherwise use the data, create a useEffect which is dependent on that value.
import React, { useContext, useEffect, useState } from 'react';
import { useParams } from 'react-router';
import RestaurantFinder from '../api/RestaurantFinder';
import { RestaurantsContext } from "../context/RestaurantsContext";
import Reviews from '../components/Reviews';
import StarComponent from '../components/StarComponent';
import AddReview from '../components/AddReview';
import Test from '../components/Test';
const RestaurantDetailedPage = (props) =>{
const{ selectedRestaurant, setSelectedRestaurant}= createContext(RestaurantsContext);
const {id} = useParams();
useEffect(()=>{
const fetchData = async(id)=>{
const result = await RestaurantFinder.get("/"+id);
console.log(result);
setSelectedRestaurant(result.data.data);
}
fetchData(id);
},[]);
useEffect(()=>{
console.log("Selected Restaurant:", selectedRestaurant);
},[selectedRestaurant]);
return(
<div>{selectedRestaurant && (
<>
<div>{<AddReview/>}</div>
<div></div>
</>
)}
</div>
)
}
export default RestaurantDetailedPage;
Original comment
With that in mind, your <Reviews> element is commented out, is that intentional?
{/* <Reviews reviewsObject={selectedRestaurant.reviews}/>*/}

React.js - passing functions between components using Context API - not working

I am trying to pass a function between two components but even though I do not have any errors, the function that I am passing wont show or to be precise it is not working. I have two files and one of them is creating a context while the other is using it (obviously). Now, they are not shown in App.js (which is rendered in index.js, usual stuff) they are in the seperate folder. I am using React Router to show one the pages (News.js).
Here are the files:
NewsContext.js
import React, { useContext, createContext, useState, useEffect } from "react";
export const newsK = React.createContext();
export const NewsContext = (props) => {
const working = () => {
console.log("it is working");
};
return <newsK.Provider value={working}>{props.children}</newsK.Provider>;
};
export default NewsContext;
News.js
import React, { useContext, useState, useEffect } from "react";
import { newsK } from "./NewsContext";
import { NewsContext } from "./NewsContext";
const News = () => {
const data = useContext(newsK);
return (
<NewsContext>
<div>
<button onClick={data}></button>
</div>
</NewsContext>
);
};
export default News;
When i pressed the button, it wont do anything. Any tips?
You're trying to use context outside the NewsContext component
The solution for this will be to create a component that will call useContext inside NewsContext.
I.e.
const WrappedButton = () => {
const data = useContext(newsK)
return <button onClick={data} />
}
And then put it inside the NewsContext:
<NewsContext>
<div>
<WrappedButton />
</div>
</NewsContext>

Resources