I am creating a CommentBox.
I am trying to refresh the comment list after form submission.
#CommentBox.js
const CommentBox = (props) => {
return (
<div className="comment_area clearfix mb-5">
<div className="section-heading style-2 mb-5">
<h4>Comment</h4>
<div className="line"></div>
</div>
< CommentForm />
< CommentList />
</div>
);
}
As you can see I have different components for CommentForm.js and CommentList.js
#CommentForm.js
const onSubmitHandler = (e) => {
........
axios.post(......................)
................................
}
return (
<form onSubmit={onSubmitHandler}>
|
|
</form>
);
#CommentList.js
useEffect(() => {
const id = props.postId;
const fetchData = async () => {
try {
const res = await axios.get(
`.......................`
)
setComments(res.data.results);
} catch (err) {}
};
fetchData();
}, [props.postId])
return (
.................
.................
......
)
How should I write the GET Method in form onsubmitHandler().
Or I have to change some other things to make it work.
A way to solve this is to move the state to your parent component, that is, make the axio calls to the parent component CommentBox. The CommentForm notifies the parent via callback that the form has been submitted and then you link one axios call after the other, passing the GET results to CommentList.
const CommentBox = (props) => {
const [comments, setComments] = useState([]);
const onSubmitHandler = (e) => {
........
axios.post(.......)
.then(() => axios.get())
.then((res) => setComments(res.data);
}
return (
<div className="comment_area clearfix mb-5">
<div className="section-heading style-2 mb-5">
<h4>Comment</h4>
<div className="line"></div>
</div>
< CommentForm onSubmit={onSubmitHandler}/>
< CommentList comments={comments}/>
</div>
);
}
Related
Currently learning React and building a side project where i can render rss-feeds in my browser window. It works in a single component.
Original working component
function App (){
const [rssUrl, setRssUrl] = useState('');
const [items, setItems] = useState([]);
const getRss = async (e) => {
e.preventDefault();
const urlRegex =
/(http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,#?^=%&:\/~+#-]*[\w#?^=%&\/~+#-])?/;
if (!urlRegex.test(rssUrl)) {
return;
}
const res = await fetch(`https://api.allorigins.win/get?url=${rssUrl}`);
const { contents } = await res.json();
const feed = new window.DOMParser().parseFromString(contents, 'text/xml');
const items = feed.querySelectorAll('item');
const feedItems = [...items].map((el) => ({
link: el.querySelector('link').innerHTML,
title: el.querySelector('title').innerHTML,
author: el.querySelector('author').innerHTML,
}));
setItems(feedItems);
};
}
return (
<div className="App">
<form onSubmit={getRss}>
<div>
<h1>Next Pod For Chrome</h1>
<label> rss url</label>
<br />
<input onChange={(e) => setRssUrl(e.target.value)} value={rssUrl} />
</div>
<input type="submit" />
</form>
{items.map((item) => {
return (
<div>
<h1>{item.title}</h1>
<p>{item.author}</p>
<a href={item.link}>{item.link}</a>
</div>
);
})}
</div>
);
}
export default App;
At the moment I try to separate the functionality into two components. How can I pass a link from one component to another one where I want to trigger a function handled by the first component?
Any tips are much appreciated. Thanks.
Current state of component to search for rss-feed
function Search() {
const [rssUrl, setRssUrl] = useState('');
const formatRss = async (e) => {
e.preventDefault();
const urlRegex =
/(http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,#?^=%&:\/~+#-]*[\w#?^=%&\/~+#-])?/;
if (!urlRegex.test(rssUrl)) {
return;
}
console.log(rssUrl);
};
return (
<div className="App">
<form onSubmit={formatRss}>
<div>
<h1>Next Pod For Chrome</h1>
<label>rss url</label>
<br />
<input onChange={(e) => setRssUrl(e.target.value)} value={rssUrl} />
</div>
<input type="Submit" />
</form>
</div>
);
}
export default Search;
Current stage of component to parse and render
function List(props) {
const [items, setItems] = useState([]);
const formatRss = async (e) => {
e.preventDefault();
console.log(rssUrl);
const res = await fetch(`https://api.allorigins.win/get?url=${rssUrl}`);
const { contents } = await res.json();
const feed = new window.DOMParser().parseFromString(contents, 'text/xml');
const items = feed.querySelectorAll('item');
const feedItems = [...items].map((el) => ({
link: el.querySelector('link').innerHTML,
title: el.querySelector('title').innerHTML,
author: el.querySelector('author').innerHTML,
}));
setItems(feedItems);
};
return (
<div className="App">
{items.map((item) => {
return (
<div>
<h1>{item.title}</h1>
<p>{item.author}</p>
<a href={item.link}>{item.link}</a>
</div>
);
})}
</div>
);
}
export default List;
You can declare the state on both's parent, for example: App.js
And use prop to pass the variable to the component
like this:
export default function App() {
const [rssUrl, setRssUrl] = useState("");
return (
<div className="App">
<Search rssUrl={rssUrl} setRssUrl={setRssUrl} />
<List rssUrl={rssUrl} />
</div>
);
}
Below is the live example for you:
https://codesandbox.io/s/cocky-tharp-7d5uu8?file=/src/App.js
There are many platforms where you can put the demo project which make it easier for people to answer your question.
I would like to pull the const ChatLog out of the main function Chats and insert it as a component or outside of the Chats function for now. The Problem is that the ChatLog needs the useState variables [msg, sendMsg] (..) that are called in the Chats function. How could I do this anyway? Am new to react.
function Chats() {
const [msg, sendMsg] = useState("");
const [msgs1, sendMsgAll] = useState([]);
useEffect(() => {
onValue(ref(database), (snapshot) => {
sendMsgAll([]);
const data = snapshot.val();
if (data !== null) {
Object.values(data).map((msg) => {
sendMsgAll((oldArray) => [...oldArray, msg]);
});
}
});
}, [])
const ChatLog = () => {
return (
<div>
{msgs1.map((msg) => (
<div className="chat-log">
<p align = {checkSide(msg.usr)}>
<h2>{msg.msg}</h2>
<h4>User: {msg.usr}</h4>
<h4>Time: {convertUnix(msg.time)}</h4>
<button>update</button>
<button>delete</button>
</p>
</div>
))}
</div>
)
}
return (
<div className="ChatView">
<p><ChatLog /></p>
<p>{ChatInput()}</p>
</div>
)
};
You can add props to ChatLog component. Check this...
const ChatLog = (props) => {
const {msg1} = props
return (
<div>
{msgs1.map((msg) => (
<div className="chat-log">
<p align = {checkSide(msg.usr)}>
<h2>{msg.msg}</h2>
<h4>User: {msg.usr}</h4>
<h4>Time: {convertUnix(msg.time)}</h4>
<button>update</button>
<button>delete</button>
</p>
</div>
))}
</div>
)
}
However,you need add props to component when you use it. Something like this...
return (
<div className="ChatView">
<p><ChatLog msg1={msg1} /></p>
<p>{ChatInput()}</p>
</div>
)
One more thing, when you declaring a component, it has to be declared of another component. Like this
//this is ChatLog component
const ChatLog = (props)=>{
return <div/>
}
//this is Chats component
const Chats = ()=>{
return (
<div>
<ChatLog {...props}/>
</div>
)
}
When I click on the Delete button, my code does not work. There could be a problem in the function handleRemove.
import React, { useState, useEffect } from 'react'
import axios from 'axios'
// API endPoint - Punk API
const API_URL = 'https://api.punkapi.com/v2/beers'
const List = () => {
const [drinks, setDrinks] = useState([])
const [searchTerm, setSearchTerm] = useState('')
const fetchData = async () => {
const { data } = await axios.get(API_URL)
setDrinks(data)
}
useEffect(() => {
fetchData()
}, [])
const handleRemove = (id) => {
let groupd = drinks
const newList = groupd.filter(group => group.id !== id)
setDrinks(newList)
}
return (
<div>
<div className="wrapper">
<div className="search__main">
<input type='text' placeholder="search..." onChange={e => {setSearchTerm(e.target.value)}}/>
</div>
</div>
<div className="wrapper">
<div className="search__box">
{drinks.filter((val) => {
if(searchTerm === ""){
return val
} else if(val.name.toLowerCase().includes(searchTerm.toLowerCase()) || val.description.toLowerCase().includes(searchTerm.toLowerCase())){
return val
}
}).map((drink, key) => {
return(
<div key={key} className="search__mini__box">
<div >
<img src={drink.image_url} alt="drink" className="search__img"/>
</div>
<h4>{drink.name}</h4>
<p>{drink.description}</p>
<button type="button" onClick={handleRemove(drink.id)}>
delete
</button>
</div>
)
})}
</div>
</div>
</div>
)
}
export default List
Since your handleRemove function call is within a return statement, you need to call the function like so:
onClick={() => handleRemove(drink.id)}
What happens is, the function is called immediately on render if done the way you've proposed in your question. We want the function to be called only when the button is clicked.
so i have two components a Child "Board.js" that bring an array from backend and build a Board it looks like this:
const Board = (props) => {
const [data, setData] = useState([]);
const newBoard = async (e) => {
e.preventDefault();
const data = await fetch('http://localhost:8080/viergewinnt/newboard')
.then(response => response.json())
.then(data => {
// console.log(data);
return data
})
const arr =[];
data.map(d => arr.push([...d]))
console.log(arr);
setData(arr);
}
return (
<div className='center'>
<div className='board'>
{ data.map((d) => d.map((v, index) => (<BoardTile key ={index}/>)))}
</div>
</div>
)
and a parent component "NewGame" which has a button, this button when clicked must build that board in child component. The Parent component looks like this:
const NewGame = (props) => {
const onClickHandler = () =>{
return (<Board></Board>)
}
return (
<div className="App">
<div>
<button className='btn' onClick={onClickHandler}>Start new game</button>
</div>
</div>
);
PS. the Board was built successfully when all the code was in one Component.
import Board from './example.js';
import { useState } from 'react';
const NewGame = (props) => {
const [boardIsVisible, setBoardIsVisible] = useState(false);
return (
<div className="App">
<div>
<button
className='btn'
onClick={() => setBoardIsVisible(true)}>
Start new game
</button>
{boardIsVisible && <Board />}
</div>
</div>
);
}
I am trying to organize my code order to handle feed as feed.* based on my endpoint API, but however react doesn't allow me to directly send functions into component, but I want something similar to feed.results, feed. count
const [initialized, setIntialized] = useState(false);
const [feed, setFeed] = useState([]);
const browserFeed = async () => {
const response = await browse();
setFeed(response.results);
setIntialized(true);
};
useEffect(() => {
if (!initialized) {
browserFeed();
}
});
export const browse = () => {
return api.get('xxxxxxxx')
.then(function(response){
return response.data // returns .count , .next, .previous, and .results
})
.catch(function(error){
console.log(error);
});
}
<div className="searched-jobs">
<div className="searched-bar">
<div className="searched-show">Showing {feed.count}</div>
<div className="searched-sort">Sort by: <span className="post-time">Newest Post </span><span className="menu-icon">▼</span></div>
</div>
<div className="job-overview">
<div className="job-overview-cards">
<FeedsList feeds={feed} />
<div class="job-card-buttons">
<button class="search-buttons card-buttons-msg">Back</button>
<button class="search-buttons card-buttons">Next</button>
</div>
</div>
</div>
</div>
If it is pagination you are trying to handle here is one solution:
async function fetchFeed(page) {
return api.get(`https://example.com/feed?page=${page}`);
}
const MyComponent = () => {
const [currentPage, setCurrentPage] = useState(1);
const [feed, setFeed] = useState([]);
// Fetch on first render
useEffect(() => {
fetchFeed(1).then((data) => setFeed(data));
}, []);
// Update feed if the user changes the page
useEffect(() => {
fetchFeed(currentPage).then((data) => setFeed(data));
}, [currentPage]);
const isFirstPage = currentPage === 1;
return (
<>
<FeedsList feeds={feed} />
{isFirstPage && (
<button onClick={() => setCurrentPage(currentPage - 1)}>Back</button>
)}
<button Click={() => setCurrentPage(currentPage + 1)}>Next</button>
</>
);
};