I tried a lots of things , and this problem does not seem to go away , can someone help me with this ??
this is my app component :
function App() {
const [todo, setTodo] = useState([]);
async function getTodo() {
try {
const todo = await axios.get("http://localhost:5000/api/todos");
// console.log(todo.data)
setTodo(todo.data);
} catch (error) {
console.log("something is wrong");
}
}
useEffect(() => {
// Update the document title using the browser API
getTodo();
}, []);
return (
<div className="App">
<h1>My Todo List</h1>
<h2>My Todo List</h2>
<Task Todor={todo} />
<Write />
</div>
);
}
export default App;
and this is my todos component :
function Todos({ Todor }) {
return (
<div className="Todos">
{Todor.map(T => <Todo post={T} />)}
</div>
);
}
export default Todos;
and this is my todo component :
function Todo({ post }) {
return (
<div className="Todo">
<h2>{post.title}</h2>
</div>
);
}
export default Todo ;
and this my add component :
export default function Write() {
const [inputText, setInputText] = useState({
title: ""
});
function handleChange(e) {
setInputText({
...inputText,
[e.target.name]: e.target.value,
});
}
const [status, setStatus] = useState(false);
async function addItem(e) {
e.preventDefault();
const res = await axios.post("http://localhost:5000/api/todos", inputText);
setInputText(inputText)
console.log("response:", res)
setStatus(true);
setInputText("");
}
return (
<div className="container">
<div className="form">
<input onChange={handleChange} type="text" name="title" />
<button onClick={addItem}>
<span>Add</span>
</button>
</div>
</div>
);
}
the new items dont show until I refresh the page , how to do that without refreshing ?
because obviously that defeats the purpose of React !!
useEffect(() => {
// Update the document title using the browser API
getTodo();
}, []);
The code inside useEffect with empty dependencies array [] only runs on the first render, to run it on every render you should remove the empty array dependencies.
useEffect(() => {
// Update the document title using the browser API
getTodo();
});
Note: It is not a best practice because your component will invoke getTodo() every time rerendered. In your case, you can use a state variable to control where to re-run the getTodo funtion e.g:
const [isAddedSuccess, setIsAddedSuccess] = useState(false)
Everytime you add new item successfully, just setIsAddedSuccess(true) and your useEffect should look like below:
useEffect(() => {
// Update the document title using the browser API
if (isAddedSuccess) getTodo();
}, [isAddedSuccess]);
Related
I'm new to react, and I would like to change the value of docUrn={urn} in viewer, if localstorage(urn) changes.
Currently I have to reload the page. I think my code is incomplete but I don't know what I'm missing.
function App() {
//const urn = "urn:my_urn";
const [urn, setUrn] = React.useState(null);
useEffect(() => {
setUrn(localStorage.getItem('urn'));
window.addEventListener('storage', (e) => {
setUrn(localStorage.getItem('urn'));
}
);
}, []);
return (
<>
<div className="App">
<Tree />
<Viewer
getToken={renewExpiredToken}
docUrn={urn}
extensions={{}}
/>
</div>
</>
);
}
This is my project for business card app.
I have a problem with using state and props between components.
Component tree looks like this.
Editor <- CardEditForm <- ImageFileInput
The url state is in the Editor component. There is a function to update state and give it as props to child components. When I upload an image on ImageFileInput component, url data goes up until the editor component and then using setUrl to url be updated. And then I gave url to CardEditorForm component.
The problem is this, In cardEditorForm, when it comes to using url props, I can't get the updated url. Only gets the initial state. I really need to get an updated url. I also tried to use setTimeout() to get the updated url. But it doesn't work either. What can I do?..
It's my first time to ask a question on stack overflow. Thank you for helping the newb.
Here is the code.
editor.jsx
const Editor = ({ cards, deleteCard, createOrUpdateCard }) => {
const [url, setUrl] = useState('');
const updateUrl = (src) => {
setUrl(src);
};
return (
<section className={styles.editor}>
<h1 className={styles.title}>Card Maker</h1>
{Object.keys(cards).map((key) => (
<CardEditForm
key={key}
card={cards[key]}
onDelete={deleteCard}
onUpdate={createOrUpdateCard}
updateUrl={updateUrl}
url={url}
/>
))}
<CardAddForm onAdd={createOrUpdateCard} updateUrl={updateUrl} url={url} />
</section>
);
};
card_edit_form.jsx
const CardEditForm = ({ card, onDelete, onUpdate, updateUrl, url }) => {
// ...
const changeUrl = () => {
setTimeout(() => {
const newCard = {
...card,
fileURL: url,
};
onUpdate(newCard);
}, 4000);
};
return (
<form className={styles.form}>
// ...
<div className={styles.fileInput}>
<ImageFileInput updateCard={changeUrl} updateUrl={updateUrl} />
</div>
// ...
</form>
);
};
export default CardEditForm;
image_file_input.jsx
const ImageFileInput = ({ updateUrl, updateCard }) => {
const [image, setImage] = useState('');
const upload = new Upload();
const onUpload = (e) => {
e.preventDefault();
upload.uploadImage(image).then((data) => updateUrl(data));
updateCard(e);
};
return (
<div>
<input type="file" onChange={(e) => setImage(e.target.files[0])} />
<button name="fileURL" onClick={onUpload}>
image
</button>
</div>
);
};
I'd like to display data fetched from API. The API url is based on user input. Once a user inputs and clicks submit, it is supposed to display the fetched data. But before user click submit, it should display nothing.
The problem I have is, when rendering the a user's data in lists in html, the map function doesn't exist on property{}, before user input anything. What should i set as the initial state?
The transformedData works fine. console.log(transformedData) prints
I'd like to display every title as a list. Example user input can be 0x147412d494731cbb91dbb5d7019464a536de04dc
import { useState } from "react";
// example user: 0x147412d494731cbb91dbb5d7019464a536de04dc
function App() {
const [data, setData] = useState({});
const [enteredWallet, setEnteredWallet] = useState("");
const [owner, setOwner] = useState("");
const walletChangeHandler = (event) => {
setEnteredWallet(event.target.value);
};
const submittedHandler = (event) => {
event.preventDefault();
setOwner(enteredWallet);
fetchNFTHandler();
};
function fetchNFTHandler() {
fetch(
`https://api.opensea.io/api/v1/assets?owner=${owner}&order_direction=desc&offset=0&limit=10`
)
.then((res) => {
return res.json();
})
.then((data) => {
const transformedData = data.assets.map((element, index) => {
return {
title: element.name,
id: index,
};
});
setData(transformedData);
console.log(transformedData);
});
}
return (
<div className="App">
<header className="App-header">
<h3>Show me assets in this wallet</h3>
<form onSubmit={submittedHandler}>
<input
placeholder="wallet address"
value={enteredWallet}
onChange={walletChangeHandler}
/>
<button>Submit</button>
</form>
<div>
console.log(data)
{/* {data.map((element) => (<li key={element.id}>
{element.title}</li>))}
*/}.
{/* here is the problem. before user input, this map function doesn't work */}
</div>
</header>
</div>
);
}
export default App;
I am building a blogging application. This application has frontend built with ReactJS and backend built with Python (Django Framework). The frontend and backend are connected with Django REST API Framework.
This post is on ReactJS Frontend.
I am using Functional Component. There is a "BlogList" Component where all blogs fetched from API endpoints will be displayed. I created a "BlogForm" Component where I have to enter 2 fields: "Title" and "Content" to create blog post. I imported the "BlogForm" Component inside "BlogList" Component to show it on the same page.
Please see this image to get a good understanding
When I enter "Title" and "Content" inside "BlogForm" Component and click on "Submit" button, data is saved in database using API call. But the added data is not showing in the "BlogList" Component at that time. I have to refresh the page to see the new blog post in the blog list.
Can anyone in the community help me to solve the problem that how can I instantly view the added blog post when I click on "Submit" button?
For your kind reference, the code is as below.
BlogList.js
import BlogForm from './BlogForm'
const BlogList = (url) => {
const [blogs, setBlogs] = useState([])
useEffect(() => {
async function fetchBlogData() {
const url = requests.blogList
const request = await axios.get(url)
setBlogs(request.data)
return request
}
fetchBlogData()
}, [url])
return (
<Wrapper>
<BlogWrapper className="blog">
// Blog Form Component Added
<BlogForm />
<div className="blog__header">
<h1 className="blog__header--title">
Information
</h1>
</div>
<hr className="blog__divider"/>
<div className="blog__list">
<ul>
<li className="blog__item">
{ blogs.map( (blog) => (
<div className="blog__item--container" key={ blog.id }>
<h1 className="blog__item--title">
<a className="blog__item--title blog__item--title--link" href={`/blog/${ blog.id }`}>
{ blog.title }
</a>
</h1>
<small className="blog__item--date">{ blog.date_published }</small>
<p className="blog__item--content">{ blog.content }</p>
</div>
) ) }
</li>
</ul>
</div>
</BlogWrapper>
</Wrapper>
)
}
export default BlogList
BlogForm.js
const BlogForm = () => {
const [inputValues, setInputValues] = useState({
title : '',
content : ''
})
const handleSubmit = async (event) => {
event.preventDefault()
setInputValues({ ...inputValues })
const { title, content } = inputValues
const blogPost = { title, content }
const url = requests.blogCreate
const response = await axios.post(url, blogPost)
return response
}
const handleChange = (name) => (event) => {
setInputValues({ ...inputValues, [name] : event.target.value })
}
return (
<div>
<form onSubmit={ handleSubmit }>
<input type="text" name="title" placeholder="Title" required value={ inputValues.title } onChange={ handleChange('title') }/>
<input type="text" name="content" placeholder="Content" required value={ inputValues.content } onChange={ handleChange('content') }/>
<button type="submit">Submit</button>
</form>
</div>
)
}
export default BlogForm
UPDATED
After the answer from DrewReese, I updated my code and I am getting error when I try to add a new Blog Post. It is showing undefined
BlogList has the state you want to be updated from the child component BlogForm. You can pass a callback from parent to child for BlogForm to call with the updated posts.
BlogList
const BlogList = (props) => {
const [blogs, setBlogs] = useState([]);
useEffect(() => {
async function fetchBlogData() {
const url = requests.blogList;
const request = await axios.get(url);
setBlogs(request.data);
}
fetchBlogData();
}, [props]);
// (1) Define a callback to update state
const addNewPost = post => setBlogs(posts => [...posts, post]);
return (
<Wrapper>
<BlogWrapper className="blog">
// Blog Form Component Added
<BlogForm addNewPost={addNewPost} /> // <-- (2) pass callback
...
</BlogWrapper>
</Wrapper>
);
}
BlogForm
const BlogForm = ({ addNewPost }) => { // <-- (3) destructure callback
const [inputValues, setInputValues] = useState({
title : '',
content : ''
})
const handleSubmit = async (event) => {
event.preventDefault()
setInputValues({ ...inputValues });
const { title, content } = inputValues;
const blogPost = { title, content };
const url = requests.blogCreate;
const response = await axios.post(url, blogPost);
addNewPost(response.data); // <-- (4) call callback with new post data
}
...
return (
...
);
}
I have a simple app for searching a db of Albums by artist.
Three components: App, AlbumList, AlbumSearch.
The App component defines getAlbumsByArtist to fetch and update albums,
and passes albums as prop to AlbumList.
App defines getAlbumsByArtist to pass as prop to AlbumSearch.
In AlbumSearch, when the artist is changed, I useEffect to call getAlbumsByArtist.
The app works, but in AlbumSearch I get a warning of
React Hook useEffect has a missing dependency: 'getAlbumsByArtist'.
How can I refactor to fix this warning?
import React, { useState, useEffect } from "react";
function App() {
const [albums, setAlbums] = useState(false);
useEffect(() => {
getAlbums();
}, []);
function getAlbums() {
fetch("http://localhost:3001")
.then((response) => response.json())
.then((data) => setAlbums(data));
}
function getAlbumsByArtist(artist) {
fetch(`"http://localhost:3001"/albums?artist=${artist}`)
.then((response) => response.json())
.then((data) => setAlbums(data));
}
return (
<div>
<h2>Albums</h2>
<AlbumSearch getAlbumsByArtist={getAlbumsByArtist} />
<AlbumList albums={albums} />
</div>
);
}
function AlbumSearch({ getAlbumsByArtist }) {
const [artist, setArtist] = useState("");
useEffect(() => {
getAlbumsByArtist(artist);
}, [artist]);
const handleArtist = (e) => {
e.preventDefault();
setArtist(e.target.value);
};
return (
<div className={`album-search ${showSearchClass}`}>
<div>
<label>Artist contains: </label>
<input
id="searchArtist"
type="text"
value={artist}
onChange={handleArtist}
/>
</div>
</div>
);
}
function AlbumList({ albums }) {
return (
<div>
<header>
<div>Id</div> <div>Artist</div> <div>Title</div>{" "}
</header>
<div>
{albums &&
albums.map((album) => {
return (
<div key={album.id}>
<div>{album.id}</div>
<div>{album.artist}</div>
<div>{album.title}</div>
</div>
);
})}
</div>
</div>
);
}
As react will guarantee that a setState() function will never change, you can simply add the getAlbumsByArtist function to your useEffect() dependencies to get the same result.
useEffect(() => {
getAlbumsByArtist(artist);
}, [getAlbumsByArtist, artist]);
Another way would be to simply irgnore the warning by:
useEffect(() => {
getAlbumsByArtist(artist);
}, [getAlbumsByArtist, artist]); // eslint-disable-line react-hooks/exhaustive-deps