I have a problem that when I search a Data in my firebase database with react dom js , i cann't get my expected data. Basically, I dont get any data at this time.
export default function SearchBar(){
const [data, setData] = useState([]);
const [search, setSearch] = useState("");
useEffect(() => {
fetch('<URL ...>')
.then(response => response.json())
.then(data => {
// console.log(data);
if(data>0){
setData(data)
}
// console.log(search);
// console.log(data);
})
.catch(error => console.error(error));
}, [search]);
return <Form>
<Input type="text" value={search} placeholder="Searching ..." onChange={event => setSearch(event.target.value)} />
<div className="" style={{height:"18px", color:'red'}}>
{data.filter(item => item.toLowerCase().includes(search.toLowerCase())).map(item => (
<div key={item}>
{console.log(item)}
</div>
))
}
</div>
<Button type="submit"><span class="material-symbols-outlined ">
search
</span>
</Button>
</Form>
}
I expect Get Data from my Firebase which i serach in my serachBox.
Related
Given the following form, I need whenever the form is submitted, the new post to be listed/rendered without having to refresh the page.
const PostCreate = () => {
const [title, setTitle] = useState('');
const onSubmit = async (event) => {
event.preventDefault();
await axios.post(`http://${posts_host}/posts/create`, {title}).catch(error => {
console.log(error)
})
setTitle('');
};
return (<div>
<form onSubmit={onSubmit}>
<div className="form-group">
<label>Title</label>
<input value={title} onChange={event => setTitle(event.target.value)}
className="form-control "/>
</div>
<button className="btn btn-primary">Submit</button>
</form>
</div>)
}
export default PostCreate;
I tried adding this.forceUpdate() and this.setState(this.state), neither works, and I still have to refresh the page for the new post to show.
Here's how the posts are rendered:
const PostList = () => {
const [posts, setPosts] = useState({});
const fetchPosts = async () => {
await axios.get(`http://${queries_host}/posts`).then(response => {
setPosts(response.data);
}).catch(error => {
console.log(error)
});
};
useEffect(() => {
fetchPosts();
}, []);
const renderedPosts = Object.values(posts).map(post => {
return <div className="card"
style={{width: '30%', marginBottom: '20px'}}
key={post.id}>
<div className="card-body">
<h3>{post.title}</h3>
<CommentList comments={post.comments}></CommentList>
<CommentCreate postId={post.id}></CommentCreate>
</div>
</div>
});
return <div>
{renderedPosts}
</div>;
}
export default PostList;
This is what App.js looks like
const App = () => {
return <div>
<h1>Create Post</h1>
<PostCreate></PostCreate>
<hr/>
<h1>Posts</h1>
<PostList></PostList>
</div>;
};
export default App;
and is eventually rendered using:
ReactDOM.render(
<App></App>,
document.getElementById('root')
)
In your PostList, useEffect called once when you first load your component, so when you create new post, it will not be re-rendered
You should bring your fetchPost logic to your App component, and add function props onPostCreated to PostCreate component, trigger it after you finish creating your new post
The code should be:
const App = () => {
const [posts, setPosts] = useState({});
const fetchPosts = async () => {
await axios.get(`http://${queries_host}/posts`).then(response => {
setPosts(response.data);
}).catch(error => {
console.log(error)
});
};
useEffect(() => {
fetchPosts();
}, []);
return <div>
<h1>Create Post</h1>
<PostCreate onCreatePost={() => fetchPost()}></PostCreate>
<hr/>
<h1>Posts</h1>
<PostList posts={posts}></PostList>
</div>;
};
export default App;
const PostList = ({ posts }) => {
const renderedPosts = Object.values(posts).map(post => {
return <div className="card"
style={{width: '30%', marginBottom: '20px'}}
key={post.id}>
<div className="card-body">
<h3>{post.title}</h3>
<CommentList comments={post.comments}></CommentList>
<CommentCreate postId={post.id}></CommentCreate>
</div>
</div>
});
return <div>
{renderedPosts}
</div>;
}
export default PostList;
const PostCreate = ({ onCreatePost }) => {
const [title, setTitle] = useState('');
const onSubmit = async (event) => {
event.preventDefault();
await axios.post(`http://${posts_host}/posts/create`, {title}).catch(error => {
console.log(error)
})
onCreatePost && onCreatePost();
setTitle('');
};
return (<div>
<form onSubmit={onSubmit}>
<div className="form-group">
<label>Title</label>
<input value={title} onChange={event => setTitle(event.target.value)}
className="form-control "/>
</div>
<button className="btn btn-primary">Submit</button>
</form>
</div>)
}
export default PostCreate;
I think the problem you are having is not in the code you have displayed. The component is indeed rerendering after you change its state and also when you forceUpdate() it. I assume the posts you are trying to display are taken from the same API that you post to. Even if this component is being rerendered, your GET request which gives the data to the component who renders it is not called again so the data doesn't update. You need to refetch it. This can be done by many different ways (useEffect(), callbacks, reactQuery refetch) depending on the rest of your code. I would need the component that renders the data and the API call to help you further.
Another thing that you didn't ask but is good practice. In your PostCreate component you don't need to manage the state of fields that are in the form, because it already does it for you. Just give a name to your inputs and use the form data. I've given an example below.
import { useState } from "react";
const PostCreate = () => {
const onSubmit = async (event) => {
event.preventDefault();
console.log(event.target.elements.title.value);
};
return (
<div>
<form onSubmit={onSubmit}>
<div className="form-group">
<label>Title</label>
<input name="title" className="form-control" />
</div>
<button className="btn btn-primary">Submit</button>
</form>
</div>
);
};
export default PostCreate;
I have a form that collect data about today's expenditure and total users(as attendances) and then submit it using redux dispatch via action addExpenses(). But it douse not run. It seem that it is not counting if it is present or not.
function TodayExpenses() {
const dispatch = useDispatch()
const navigate = useNavigate()
useEffect(() => {
dispatch(getAttendance());
}, [date, getAttendanceObj, dispatch, addExpenses])
const [todayExpenses, setTodayExpenses] = useState(0)
const { attendance: getAttendanceObj, error: getAttendanceError, loading: getAttendanceLoading } = useSelector(state => state.getAttendance)
const { success } = useSelector(state => state.addExpenses)
const submitHandler = (e) => {
e.preventDefault();
let expenses = {
date: date,
total_attendances: count,
expenses_per_day: todayExpenses,
expenses_per_attendance: expensePerAttendance,
}
dispatch(addExpenses(expenses)) // Here be the dragons
console.log(todayExpenses)
}
const today = new Date().toISOString().substr(0, 10);
const [date, setDate] = useState(today)
const count = counter(getAttendanceObj, date)
const expensePerAttendance = (todayExpenses / count).toFixed(2);
return (
<div className="container">
<div class="h1 text-center text-dark" id="pageHeaderTitle">
Enter <input type="date" id="date" value={date} onChange={(e) => setDate(e.target.value)} max={today} />'s Expenses
</div>
<div className="row">
<div className="col-md-6 mx-auto">
<div className="card card-body">
<form onSubmit={submitHandler}>
<label htmlFor="name">Today's Expenses:</label>
<input
type="number"
className="form-group"
id="name"
placeholder="Enter value"
value={todayExpenses}
onChange={(e) => setTodayExpenses(e.target.value)}
/>
<ul class="list-group list-group-flush">
<label class="list-group-item card-header">Total Attendances</label>
<li class="list-group-item">{count}</li>
<label class="list-group-item card-header">Expense Per Attendance</label>
<li class="list-group-item">{expensePerAttendance}</li>
</ul>
<button type="submit" className="btn btn-primary">
Submit
</button>
</form>
</div>
</div>
</div>
</div>
);
}
export default TodayExpenses;
What I have tried so far
What not? I tried console.log()even inside action but it working just above the required script ( I mean where the action have submit the data) .
if wanna ask here is action
export const addExpenses = (expenses) => async (getState, dispatch) => {
try {
dispatch({
type: ADD_EXPENSES_REQUEST
})
console.log("data:", dispatch({
type: ADD_EXPENSES_SUCCESS
}))
const { userLogin: { userInfo } } = getState();
const config = {
headers: {
'Content-type': 'application/json',
// 'Authorization': `JWT ${userInfo.token}`
}
}
const { data } = await axios.post(
'/api/expenses/post/',
expenses,
config
)
dispatch({
type: ADD_EXPENSES_SUCCESS,
payload: data
})
} catch (error) {
dispatch({
type: ADD_EXPENSES_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.response,
})
}
}
The dilemma is that I have copied it from other actions where it worked . I have also tried posting date using data manually using ThunderClient extention.(it is like insomnia or postman ) which mean there is no problem on the backend side.
Your thunk arguments are backwards. It should be (dispatch, getState)
export const addExpenses = (expenses) => async (dispatch, getState) => {
as you can see from my code I have some props({allRecipes}) fetched by Redux, I can display them with const mapRecipe =(), but I would like to filter them by a search bar, I think the solution would be the hook useEffect, but I can't go on,
useEffect(() =>{
const res = allRecipies.filter(el => el.name.toLowerCase().includes(searchTerm))
setSearchResults(res)},[searchTerm])
give to me error: allRecipies is null.
hope someone can point me on the right direction.
here the code:
const [searchTerm, setSearchTerm] = useState("");
const [searchResults, setSearchResults] = useState([]);
const handleChange = event => {
console.log("search bar",event.target.value)
setSearchTerm(event.target.value);
}
useEffect(() =>{
const res = allRecipies.filter(el => el.name.toLowerCase().includes(searchTerm))
setSearchResults(res)
},[searchTerm])
const mapRecipe =() =>{
if(!allRecipies){return<li>no fish</li>}
else{return allRecipies.map(el =>{
return (<div className="col s12 l4" key={el._id} >
<div className="card ">
<div style={{backgroundImage:`url(${staticImage})`,height:"200px",backgroundSize:"cover"}} className="card-image ">
<a className="btn-floating halfway-fab waves-effect waves-light btn-large lime darken-2"><i className="material-icons">clear</i></a>
</div>
<span className="card-title">{el.name}</span>
<div className="card-content">
<p>{el.listOfStages[0]}</p>
</div>
</div>
</div>)
})}
}
return (
<div>
<input type="text"
placeholder="search"
value={searchTerm}
onChange={handleChange}/>
<div className="row" >
{mapRecipe()}
</div>
</div>
)
}
function mapStateToProps(state){
console.log(state);
return state
}
export default connect(mapStateToProps)(Landing)
Use null propogation to get rid of that error:
useEffect(() =>{
const res = allRecipies?.filter(el => el.name.toLowerCase().includes(searchTerm))
setSearchResults(res)
},[searchTerm])
You can read more about it here : Null Propagation Operator in JavaScript
I would do this:-
detect incoming allRecipies with useEffect & apply default searchTerm:-
another useEffect for filtering searchTerm:-
// do search
const seacrh = (allRecipies, searchTerm) => {
return allRecipies.filter(el => el.name.toLowerCase().includes(searchTerm))
}
// run when 'allRecipies' present
useEffect(() => {
(() => {
if(allRecipes) {
setSearchResult(() => search(allRecipies, ''))
}
})()
}, [allRecipies])
// run when there's changes on 'searchTerm'
useEffect(() => {
(() => {
if(searchTerm) {
setSearchResult(() => search(allRecipies, searchTerm))
}
})()
}, [searchTerm])
I have a list of users for my website, however, whenever I try to make my Axios call to delete a user, I am getting stuck with an HTTP 405 Error. I believe it may have to do with how I am attempting to use the id.
User component:
const Users = () => {
const [users, setUsers] = useState({ list: [] });
useEffect(() => {
axios
.get('/api/User')
.then(response => {
setUsers({list:response.data});
})
.catch(error => {
console.log(error);
})
}, []);
const handleDelete = () => {
axios
.delete('/api/User', users.list.id)
.then(response => {
console.log(response.status)
})
.catch(error => {
console.log(error)
})
}
return(
<div className="container white">
<h3 className="center"> User List</h3>
{users.list.map(item => (
<div className="section" key={item.id}>
<div className="divider"></div>
<h5>{item.username}</h5>
<h5>{item.email}</h5>
<button className="btn-delete" onClick={handleDelete}>Delete</button>
</div>
))}
</div>
);
}
https://gyazo.com/2196c842804c7bfdfb1eb6b19ce26853
I've been trying to implement a loading functionality to my app. I'm simply changing the state of loading from false as the initial value and then true as it starts the fetch and then false as it ends the data fetching. So this should show the loading element I've set conditionally to render when loading is true. But it shows in my console.log that the value is always false.
I've tried putting the setState(true) in different places, in the onClick function but it doesn't seem to toggle to true.
import React, { useState } from "react";
import { LANGUAGES } from '../config/languages'
import { BASEURL, APIKEY } from '../config/gavagai'
export function Input(props) {
const [word, setWord] = useState("");
const [language, setLanguage] = useState("");
const [data, setData] = useState([])
const [loading, setLoading] = useState(false);
const url = BASEURL + '/' + language + '/' + word + '?additionalFields=SEMANTICALLY_SIMILAR_WORDS&apiKey=' + APIKEY;
const fetchData = () => {
giveWarning();
setLoading(true);
if (word && language) {
fetch(url)
.then(response => response.json())
.then(response => setData({ status: 'loaded', payload: response }), setLoading(false))
.catch(error => setData({ status: 'error', error }))
return data;
};
}
return (
<div>
<h1>Gavagai Lexicon</h1>
<div className="row">
<label>
Type your word here
</label>
</div>
<div className="input-field col s5">
<input
type="text"
value={word}
onChange={e => setWord(e.target.value)}
/>
</div>
<div className="input-field col s3">
<select className="browser-default" value={language} onChange={e => setLanguage(e.target.value)}>
<option value="" disabled selected>Choose your language</option>
{ LANGUAGES.map((lang) => {
return(
<option value={lang.alpha2}>{lang.English}</option>
)
})}
</select>
</div>
<div className="button-space">
<button className="btn waves-effect waves-light" onClick={() => fetchData()}>Search</button>
</div>
{
loading ? <p>loading</p> : null
}
</div>
);
}
Console.log reveals that it doesn't toggle to true. What am I missing here?
Because of closure, fetchData has only access to the initial value of word and language variables.
You need to useCallback( your function, [word, language] ) to use the current values of those.
https://reactjs.org/docs/hooks-reference.html#usecallback
export function Input(props) {
...
const fetchData = useCallback(
() => {
giveWarning();
setLoading(true);
if (word && language) {
fetch(url)
.then(response => response.json())
.then(response => setData({
status: 'loaded',
payload: response
}), setLoading(false))
.catch(error => setData({ status: 'error', error }))
return data;
};
},
[word, language]
)
...