React response get data - reactjs

I wanted to add the data of a Axios response into my useState Array. The problem is that I don't know how to get the data out of the then() function. Basically what I want to do is save the Axios response so that I can use it in my Array. (I'm trying React for the first time)
for (var i = 1; i <= props.max; i++) {
const response = Axios.get("http://localhost:3001/content", {id: 1});
response.then((res) => {
console.log(res.data[0].title)
})
blogs.push({title: "TITLE HERE", text: "text", author: "author", date: "date"}); //I want to insert the title here
}
I already tried:
const [title, setTitle] = useState();
for (var i = 1; i <= props.max; i++) {
const response = Axios.get("http://localhost:3001/content", {id: 1});
response.then((res) => {
setTitle(res.data[0].title)
})
}
Heres the complete function:
import React, { useEffect, useState, express, memo } from "react";
import './network.css';
import Axios from 'axios';
function Content(props) {
const [blogs, setBlogs] = useState([]);
const [title, setTitle] = useState();
/**const [text, setText] = useState();
const [author, setAuthor] = useState();
const [date, setDate] = useState();*/
for (var i = 1; i <= props.max; i++) {
const response = Axios.get("http://localhost:3001/content", {id: 1});
response.then((res) => {
console.log(res.data[0].title)
})
blogs.push({title: "TITLE", text: "text", author: "author", date: "date"}); //I want to insert the title here
}
return (
<div>
{blogs.map((blog) => (
<div class="card">
<div class="card-body">
<h4>{blog.title}</h4>
<p>{blog.text}</p>
<div class="user">
<img alt="user" id="image"/>
<div class="user-info">
<h5>{blog.author}</h5>
<small>{blog.date}</small>
</div>
</div>
</div>
</div>
))}
</div>
);
}
export default Content;

Please add your fetch logic on useEffect hook. Otherwise, fetch logic will be executed in every re-render.
Your app may get frozen.
And you should not change state variable blogs by blogs.push....
use setBlogs function.
And please use className instead of class in DOM.
I see many problems in the code and strongly to read react help before writing any code.
Anyway updated code is here.
function Content(props) {
const [blogs, setBlogs] = useState([]);
const [title, setTitle] = useState();
/**const [text, setText] = useState();
const [author, setAuthor] = useState();
const [date, setDate] = useState();*/
useEffect(() => {
for (var i = 1; i <= props.max; i++) {
const response = Axios.get("http://localhost:3001/content", {id: 1});
response.then((res) => {
setBlogs(res.data);
})
}
}, []);
return (
<div>
{blogs.map((blog, key) => (
<div className="card" index={key}>
<div className="card-body">
<h4>{blog.title}</h4>
<p>{blog.text}</p>
<div className="user">
<img alt="user" id="image"/>
<div className="user-info">
<h5>{blog.author}</h5>
<small>{blog.date}</small>
</div>
</div>
</div>
</div>
))}
</div>
);
}
export default Content;

You should useEffect hook for fetching data and .then should set it to the state. UseEffect will fetch data when the component is rendered, and store it in the state. Then you can display it in jsx. I recommend reading this article (which shows how to do it with Axios).
https://www.freecodecamp.org/news/how-to-use-axios-with-react/

Since Axios is a promise-based HTTP client library you will have to deal with the data only after the response is resolved. This means you have two options . 1) use setBlog inside then function completely (which is mentioned by other answers already)
2) Use async-await syntax(which is just syntactic sugar to the Promise.then() and Promise.catch())
Another thing you need to keep in mind is to try and treat your react state arrays as immutable. So you need to use the spread operator instead of the traditional push method because the push method directly mutates your state array and can lead to some dangerous and error-prone code.
It is recommended that you make you react 'state' changes in the useEffect hook or inside a function in the functional component. triggering state changes in the manner you have done can lead to infinite rendering and cause a Runtime Error.
When creating a list in the UI from an array with JSX, you should add a key prop to each child and to any of its’ children. (the key is recommended 'NOT 'to be the index of the array) Below is the code sample to set your array into the state
useEffect(()=>{
(async()=>{
for(let i=0;i<=props.max;i++){
let response = await Axios.get("http://localhost:3001/content",{id:1});
setBlogs((blog)=>[...blog,response.data]);
}
})();
});

Related

how unite two functions in to one in a functional component?

I have this react functional component, I have a problem with the rest function inside of it I have to call this function twice to change every single state any way to unite them in to one ? in classic JavaScript I would use a conditional but since I am new to react I have no clue how to achieve this yet ?
import React, {useState} from 'react'
function ChangeableItem(props) {
setNumber([props.number])
setDescribe([props.dsecribe])
}
const restNumber = (e)=> {
setNumber('')
}
const restDescribe = (e)=> {
setDescribe('')
}
return (
<li className='day-item'>
<div className='number amount' onFocus={() =>{restNumber();}}} contentEditable="true">{number}</div>
<div className='number name' onFocus={() =>{restDescribe();}}} contentEditable="true">{describe}</div>
<div className="">
{icons}
</div>
</li>
)
}
actually, you can use useEffect on this, like you store your value in a useState and retrieve it in a useEffect
such as:
const [num, setNum] = React.useState('');
const [desc, setDesc] = React.useState('');
// these functions will retrieve values for you,
// when retrieving is done, it will set value to useState so you can use it.
React.useEffect(()=>{
restNumber([props.number])
// assuming this function return a Promise
.then((val)=>{
setNum(val);
})
},[props.number])
React.useEffect(()=>{
restDescription([props.description])
// assuming this function return a Promise
.then((val)=>{
setDesc(val);
})
},[props.description])
EDIT:
if you really want to retrieve value on focus, you can just do
<div onFocus={()=>restNumber([props.number]).then((val)=>setNum(val))}>
</div>
You can use useEffect to update new props:
useEffect(() => setNumber(props.number), [props.number])
useEffect(() => setDescribe(props.dsecribe), [props.dsecribe])

Components not re render on state change

I am trying to update a state of a list. And need to rerender the list as per the ids state. But array takes reference value and everytime I update the ids with setIds, I am unable to get the updated list as the component is not rerendered. Anyway to achieve this. I have tried adding const [idsLength, setIdsLength] = useState(0) and passing and updating it in the list. But I feel there is a better approach for this.
const Component1 = () => {
const [ids, setIds] = useState([]);
const handleIdClick = () => {
const temp = ids
temp.push(ids.length)
setIds(temp)
console.log(ids)
}
return(
<div>
<div onClick={handleIdClick}>
Id Adder
</div>
{ids.map(id=>{
return(
<div key={id}>
{id}
</div>
)
})}
</div>
)
}
you just need to use useEffect hook
useEffect(() => {
console.log("ids :" + ids);
}, [ids]);
You can create and pass in a new array with updated contents to setIds
const handleIdClick = useCallback(() => {
setIds([...ids, ids.length]);
}, [ids])

React - How can I set "message from me"

I have 2 states:
const [formData, setFormData] = useState({ input: null });
const [outputData, setOutputData] = useState({ output: null });
formData is coming from my < input />. So, I am writing the input data by writing. outputData is coming from my GET api call.
I need to separate input data and output data. How can I tell the function if the message is from me?
function renderMessage(message) {
//const here
if (messageFromMe) {
return <Me />;
} else {
return <You />;
}
}
function Me(props) {
return (
<li className="Messages-message currentMember">
<div className="Message-content">
Hey its me
</div>
</li>
);
}
function You(props) {
return (
<li className="Messages-message">
<div className="Message-content">
Test
</div>
</li>
);
}
This might be a good application for useEffect hook. The useEffect hook takes 2 arguments, a callback function (this could be your renderMessage) and an array of values. Whenever a value in the array changes, useEffect will call your function passed into the first argument. The hook itself would be inside of a higher-level component that would effectively parent your You and Me components when they are rendered by the callback of the hook.
Now we can do this:
const [formData, setFormData] = useState(null);
const [outputData, setOutputData] = useState(null);
const [lastMessageSender, setLastMessageSender] = useState("");
let messageFromMe = (lastMessageSender === "me");
useEffect(()=>{renderMessage(message)}, [lastMessageSender]);
The last piece is this - whenever you call setFormData, also call setLastMessageSender and pass in the value "me" and whenever you call setOutputData, also call setLastMessageSender and pass in the value "you" - they could be other values eventually, such as the name of the user.
You may want to have convenience functions to help you code stay DRY...
const updateMessageFromOutput = payload => {
setOutputData(payload);
setLastMessageSender("you");
}
const updateMessageFromForm = payload => {
setFormData(payload);
setLastMessageSender("me");
}

React Hook useEffect() run continuously although I pass the second params

I have problem with this code
If I pass the whole pagination object to the second parameters of useEffect() function, then fetchData() will call continuously. If I only pass pagination.current_page so It will call only one time, but when I set new pagination as you see in navigatePage() function, the useEffect() does not call to fetchData() although pagination has changed.
How to solve this. Thank you very much!
Besides I do not want the use useEffect() call when first time component mounted because the items is received from props (It is fetch by server, this is nextjs project).
import React, {useEffect, useState} from 'react';
import Filter from "../Filter/Filter";
import AdsListingItem from "../AdsListingItem/AdsListingItem";
import {Pagination} from "antd-mobile";
import styles from './AdsListing.module.css';
import axios from 'axios';
const locale = {
prevText: 'Trang trước',
nextText: 'Trang sau'
};
const AdsListing = ({items, meta}) => {
const [data, setData] = useState(items);
const [pagination, setPagination] = useState(meta);
const {last_page, current_page} = pagination;
const fetchData = async (params = {}) => {
axios.get('/ads', {...params})
.then(({data}) => {
setData(data.data);
setPagination(data.meta);
})
.catch(error => console.log(error))
};
useEffect( () => {
fetchData({page: pagination.current_page});
}, [pagination.current_page]);
const navigatePage = (pager) => {
const newPagination = pagination;
newPagination.current_page = pager;
setPagination(newPagination);
};
return (
<>
<Filter/>
<div className="row no-gutters">
<div className="col-md-8">
<div>
{data.map(item => (
<AdsListingItem key={item.id} item={item}/>
))}
</div>
<div className={styles.pagination__container}>
<Pagination onChange={navigatePage} total={last_page} current={current_page} locale={locale}/>
</div>
</div>
<div className="col-md-4" style={{padding: '15px'}}>
<img style={{width: '100%'}} src="https://tpc.googlesyndication.com/simgad/10559698493288182074"
alt="ads"/>
</div>
</div>
</>
)
};
export default AdsListing;
The issue is you aren't returning a new object reference. You save a reference to the last state object, mutate a property on it, and save it again.
const navigatePage = (pager) => {
const newPagination = pagination; // copy ref pointing to pagination
newPagination.current_page = pager; // mutate property on ref
setPagination(newPagination); // save ref still pointing to pagination
};
In this case the location in memory that is pagination remains static. You should instead copy all the pagination properties into a new object.
const navigatePage = (pager) => {
const newPagination = {...pagination}; // shallow copy into new object
newPagination.current_page = pager;
setPagination(newPagination); // save new object
};
To take it a step further you really should be doing functional updates in order to correctly queue up updates. This is in the case that setPagination is called multiple times during a single render cycle.
const navigatePage = (pager) => {
setPagination(prevPagination => {
const newPagination = {...prevPagination};
newPagination.current_page = pager;
});
};
In the case of pagination queueing updates may not be an issue (last current page set wins the next render battle), but if any state updates actually depend on a previous value then definitely use the functional update pattern,

I am using React Hook correctly?

I want to apply React hook for infinite scroll. So, I end up with this code:
export default function index() {
const [allTracks, setAllTracks] = useState([]);
const [offset, setOffset] = useState("");
const { tracks, error, loading, lastVisible } = useFetchPublicTracks(
myApiEndPoint.TRENDING_TRACKS,
5,
offset
);
//concat tracks when got data successfully
useEffect(() => {
if (!loading && tracks) setAllTracks([...allTracks, ...tracks]);
}, [loading, tracks]);
console.log("tracks", allTracks);
console.log("lastVisible", lastVisible);
console.log("loading", loading);
return (
<div>
<button className="" onClick={() => setOffset(lastVisible)}>
Load More
</button>
<Main></Main>
</div>
);
}
When I click "Load More" button, new offset will be setted. After that, component re-render again and call Api with new offset.
I want ask that I am using React hook correctly ? There is any way better ? Also, Do I need to use useCallback/useMemo in my use case ?

Resources