updating array useState react hooks (Next.js) - javascript

I am trying to update my 'state' array and insert items of type String into it with 'setState' but it doesn't works.
I know it's not work with push().
I also tried to update my 'state' array with the spread operator but it also doesn't work.
Here my code:
import React, { useState } from 'react';
import _, { debounce } from 'lodash';
export default function Search() {
const [state, setState] = useState([])
const handleChange = debounce(async (value) => {
const url = `http://localhost:3100/`
if (value == '') {
return
}
let response = await fetch(url, {
headers: {
'Content-Type': 'application/json'
},
method: 'POST',
body: JSON.stringify({ value })
})
let test = await response.json()
console.log(test)
setState(state.concat(test))
// setState([...state, test]) it also doesn't work
console.log(state)
}, 1000)
return (
<>
<div>
<input onChange={e => handleChange(e.target.value)} />
</div>
</>
)
}
The 'state' array remains empty. I need to understand why please.

1.) Change if(value == '') to if(value ==='')
2.) console.log(state) after your setState will return the previous value of state as the component has not refreshed yet. Look at the example here: https://codesandbox.io/s/friendly-ives-vvo13?file=/src/App.js:103-474 and type something and look at the console. Then type something else and look at the console. You will see the console is showing the state of what you previous typed. However, if you look at the {state} rendered inside of the return, it will show you the current state.
export default function App() {
const [state, setState] = useState([]);
const handleChange = debounce(async value => {
let test = ["cars", "boat", "bike"];
setState([...test, value]);
console.log(state);
}, 1000);
return (
<>
<div>
{state}
<input onChange={e => handleChange(e.target.value)} />
</div>
</>
);
}
So you are setting state, just accessing/reading it in the wrong place.

https://codesandbox.io/s/next-js-infinite-scroll-3vfem?file=/pages/Content.js
I added one line to this function from the demo above
const getMorePost = async () => {
const res = await fetch(
`https://jsonplaceholder.typicode.com/todos?_start=${posts.length}&_limit=20`
);
const newPosts = await res.json()
setHasMore(!!newPosts.length)
setPosts((post) => [...post, ...newPosts])
}
now scroll completes ok.

Related

How to use data.map function in Reactjs

I am working on Reactjs and using nextjs,Right now i am trying to fetch data using "map" function,How can i do this ? Here is my current code
import { useEffect, useState } from "react"
export default function Test() {
const [data, setData] = useState<any>();
useEffect(() => {
const callData = async () => {
const data = await fetch('https://dummyjson.com/products').then(data => data.json())
console.log(data);
setData(data)
}
callData()
}, [])
return (
//want to use map function here
);
}
Well dummyjson will return you an object wich will contain { products, total, skip, limit } in your return you can write
{data.products.map((product) => <p key={product.id}>{product.title}</p>)}
paragraph in map can be your ArticleItem or everything you want.
so you could do this, check if the state has any data in it then map through, if not show some other message.
Not sure how your data state is structured, but this should help
return(
<div>
{
data.length ? data.map(({id: number, title: string}) => <p key={id}>{title}</p>) : do something if data is empty
}
</div>)

In react, how can I store data immediately if there's none and use it right away?

I'm having trouble using LocalStorage data.
I used storejs (localStorage library), therefore store.getItem equals to localStorage.getItem and store.setItem equals to localStorage.setItem.
please check my code.
const test = () => {
useEffect(() => {
const res = store.getItem('data')
// I'm trying toexecutes following code if store returns undefined.
if(!res) {
store.setItem('data', [{name:'aden', age:17}])
store.getItem('data')
}
},[])
return <></>
}
I know this code doesn't work. However, What I'm trying to do is when component mounts and there's nothing in LocalStorage, I want to immediately setItem to LocalStorage, and fetch the item right away.
However, with that code, I get nothing from the LocalStorage, It seems like I'm having misconception on lifecycle of react.
How can I solve the problem?
Try this:
import React, { useState } from "react";
const Test = () => {
const [user, setUser] = useState(JSON.parse(localStorage.getItem("user")));
const addToLocalStorage = () => {
const payload = [{ name: "aden", age: 17 }];
setUser(payload);
localStorage.setItem("user", JSON.stringify(payload));
};
return (
<>
<div>
{user?.length > 0 &&
user.map((e) => <span key={e.name}>name:{e.name}</span>)}
</div>
<button onClick={addToLocalStorage}>Add to localStorage</button>
</>
);
};
export default Test;
useEffect(() => {
const res = store.getItem('data')
// I'm trying toexecutes following code if store returns undefined.
if(!res) {
store.setItem('data', [{name:'aden', age:17}])
store.getItem('data')
}
},[])
Maybe you should type store.setItem

don't know why im getting error while passing array of objects as props to child component in react js

I want to pass an array as props to child component and try to create table with the use of that props using react table.
I am getting this error message when passing an array as props to Table component.
Objects are not valid as a React child (found: object with keys {continent, country, totalcases, criticalcases, activecases, deaths, recovery, newcases, death1mpop, cases1mpop}). If you meant to render a collection of children, use an array instead.
App component:
function App() {
const [totalCases, setTotalCases] = useState({});
const [countryData, setCountryData] = useState([]);
const [loading, setLoading] = useState(true);
const [loadingCountry, setLoadingCountry] = useState(true);
const getCovidData = async () => {
setLoading(true);
const res = await fetch(
"https://covid-193.p.rapidapi.com/statistics?country=all",
{
method: "GET",
headers: {
"x-rapidapi-host": "covid-193.p.rapidapi.com",
"x-rapidapi-key":
"xxxxxxxxxxxxxxxxxxxxxxxxx",
},
}
);
const data = await res.json();
const actualData = data.response[0];
setTotalCases(actualData);
setLoading(false);
// console.log(actualData);
};
const getCountriesData = async () => {
setLoadingCountry(true);
const res = await fetch("https://covid-193.p.rapidapi.com/statistics", {
method: "GET",
headers: {
"x-rapidapi-host": "covid-193.p.rapidapi.com",
"x-rapidapi-key": "xxxxxxxxxxxxxxxxxxxxxxxxx",
},
});
const data = await res.json();
console.log(data.response);
let requiredData = data.response.map((d) => {
return {
continent: d.continent,
country: d.country,
totalcases: d.cases.total,
criticalcases: d.cases.critical,
activecases: d.cases.active,
deaths: d.deaths.total,
recovery: d.cases.recovered,
newcases: d.cases.new,
death1mpop: d.deaths["1M_POP"],
cases1mpop: d.cases["1M_POP"],
};
});
console.log(requiredData);
setCountryData(requiredData);
// setCountryData(data.response);
setLoadingCountry(false);
console.log(countryData);
console.log(countryData.length);
};
useEffect(() => {
getCovidData();
getCountriesData();
}, []);
return (
<div className="App">
<h1>Covid Tracker....</h1>
{loading ? <h1>Loading data</h1> : <Details totalCases={totalCases} />}
{/* {loadingCountry ? <h1>Loading list</h1>
:
<Table countryData={countryData}/>
} */}
{/* {countryData !== undefined && <Table countryData={countryData}/>} */}
</div>
);
}
export default App;
Short Answer - The error message you are getting is absolutely correct. If you read the React Docs, Your JSX compiles to React.createElement(component, props, ...children). And yes objects cannot be children. Ref - https://reactjs.org/docs/jsx-in-depth.html#children-in-jsx
Since I don't have your sample data, I am assuming your data might be like this:
<Test arr={[{ a: 1 }, { b: 2 }, { c: 3 }]} />
I am creating a small component to render this data:
import React from "react"
function Test(props) {
return (
<div>
{props.arr.map((x, index) => {
console.log(index, x);
// return <h1 key={index}>{x}</h1>;
return <h1 key={index}>{Object.keys(x).map((y) => x[y])}</h1>;
})}
</div>
);
}
If I place object in JSX, it will throw an error (Commented Code).
Also please check the Table component (if its 3rd party lib), in which format it is expecting the data. If it's yours then you have to iterate over object using Object.entries() or Object.keys(), Object.values() to display data
Hope this answers your question. Please upvote if you find it helpful.

How to instantly display data after an API call in react hooks

I don't understand why the second line, which reads data from the props, is not displayed as instantly as the first, i would like them to be displayed instantly
I update the state when a button is clicked, which calls api, data is coming in, the state is updating, but the second line requires an additional press to display
How to display both lines at once after a call? What's my mistake?
I'm using react hooks, and i know that required to use useEffect for re-render component, i know, that how do work asynchronous call,but i'm a little confused, how can i solve my problem, maybe i need to use 'useDeep effect' so that watching my object properties, or i don't understand at all how to use 'useEffect' in my situation, or even my api call incorrectly?
I have tried many different solution methods, for instance using Promise.all, waiting for a response and only then update the state
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./test";
ReactDOM.render(<App />, document.getElementById("root"));
app.js
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
const useDataApi = (initialState) => {
const [state, setState] = useState(initialState);
const stateCopy = [...state];
const setDate = (number, value) => {
setState(() => {
stateCopy[number].date = value;
return stateCopy;
});
};
const setInfo = async () => {
stateCopy.map((item, index) =>
getFetch(item.steamId).then((res) => setDate(index, res.Date))
);
};
const getFetch = async (id) => {
if (id === "") return;
const requestID = await fetch(`https://api.covid19api.com/summary`);
const responseJSON = await requestID.json();
console.log(responseJSON);
const result = await responseJSON;
return result;
};
return { state, setState, setInfo };
};
const Children = ({ data }) => {
return (
<>
<ul>
{data.map((item) => (
<li key={item.id}>
{item.date ? item.date : "Not data"}
<br></br>
</li>
))}
</ul>
</>
);
};
const InfoUsers = ({ number, steamid, change }) => {
return (
<>
<input
value={steamid}
numb={number}
onChange={(e) => change(number, e.target.value)}
/>
</>
);
};
function App() {
const usersProfiles = [
{ date: "", id: 1 },
{ date: "", id: 2 }
];
const profiles = useDataApi(usersProfiles);
return (
<div>
<InfoUsers number={0} change={profiles.setID} />
<InfoUsers number={1} change={profiles.setID} />
<button onClick={() => profiles.setInfo()}>Get</button>
<Children data={profiles.state} loading={profiles} />
</div>
);
}
export default App;
To get the data, just click GET
In this example, completely removed useEffect, maybe i don’t understand how to use it correctly.
P.s: Sorry for bad english
You don't need stateCopy, as you have it in the callback of the setState:
const setInfo = async () => {
// we want to update the component only once
const results = await Promise.all(
state.map(item => getFetch(item.steamId))
);
// 's' is the current state
setState(s =>
results.map((res, index) => ({ ...s[index], date: res.Date })
);
};

How to make defaultValue work on select when options are generated dinamically? [duplicate]

This question already has answers here:
How can I set the default value for an HTML <select> element?
(34 answers)
Closed 1 year ago.
I have a select and the options for it are generated on a function, I'd like to set a value on the defaultValue and have the option with this value being selected by default, but it's not the way it's working right now. I have replicated the problem on this CodeSandbox: CodeSandbox.
I'm also displaying the mock data on the screen so you can check which person it should be selecting. In the code, I set the default value to be defaultValue={3}, so the user with id "3" is the one I'd want to have selected.
This is the code for those who can't access the codesandbox:
import "./styles.css";
import axios from "axios";
import { useEffect, useState } from "react";
const App = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
const fetch = async () => {
let result = await getUsers();
setUsers(
result.map((r, index) => {
let temp = r;
temp["idd"] = index;
return temp;
})
);
};
fetch();
}, []);
const generateOptions = () => {
let aux = users.map((u, key) => {
return (
<option key={key} value={u.idd}>
{u.name.first}
</option>
);
});
return aux;
};
const getUsers = async () => {
let data = [];
await axios
.get("https://randomuser.me/api/?results=10", {
headers: {
"Content-type": "application/json"
}
})
.then((r) => {
data = r.data.results;
});
return data;
};
return (
<>
{users ? (
<>
<div className="App">
<select defaultValue={3}>{generateOptions()}</select>
</div>
</>
) : (
<div>loading...</div>
)}
</>
);
};
export default App;
The issue seems to be the select component needs to re-render. If you add a key of users.length to the select it forces it to re-render and work
https://codesandbox.io/s/recursing-lake-j9h1y?file=/src/App.js

Categories