I am making a website in which I am able to send notifications to all the users but there is a problem, it says
Notification.requestPermission() is not a function
Here is my code:
import React, { useState } from "react";
const Notification = () => {
const [input, setInput] = useState("");
const handleInput = (e) => {
e.preventDefault();
setInput(e.target.value);
};
const sendNotification = () => {
Notification.requestPermission().then((perm) => {
if (perm === "granted") {
new Notification(input, {
body: "Go check it out!",
});
}
});
};
return (
<>
<input type="text" value={input} onChange={handleInput} />
<button onClick={sendNotification}>Send</button>
</>
);
};
export default Notification;
I am using react
Thank You in advance!
Related
I'm trying to map over data from API, but while writing the code to display the data I got this error: TypeError: weatherData.map is not a function
I tried removing useEffect from the code and tried to add curly brackets: const [weatherData, setWeatherData] = useState([{}])
Update: Line 14 log undefined : console.log(weatherData.response)
import axios from 'axios'
import { useEffect, useState } from 'react'
import './App.css'
function App() {
const [search, setSearch] = useState("london")
const [weatherData, setWeatherData] = useState([])
const getWeatherData = async () => {
try {
const weatherData = await axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${search}&appid={APIKEY}`);
console.log(weatherData.response);
if (weatherData) {
setWeatherData(weatherData);
}
} catch (err) {
console.error(err);
}
}
useEffect(() => {
getWeatherData()
}, [getWeatherData])
const handleChange = (e) => {
setSearch(e.target.value)
}
return (
<div className="App">
<div className='inputContainer'>
<input className='searchInput' type="text" onChange={handleChange} />
</div>
{weatherData.map((weather) => {
return (
<div>
<h1>{weather.name}, {weather.country}</h1>
</div>
)
})}
</div>
)
}
export default App
You're having errors in fetching the data as well as rendering it.
Just change the entire App component like this :
import { useEffect, useState } from "react";
import axios from "axios";
function App() {
const [search, setSearch] = useState("London");
const [weatherData, setWeatherData] = useState([]);
const APIKEY = "pass your api key here";
useEffect(() => {
const fetchData = async () => {
const result = await axios(
`https://api.openweathermap.org/data/2.5/weather?q=${search}&appid=${APIKEY}`
);
setWeatherData(result.data);
};
fetchData();
}, [search]);
const handleChange = (e) => {
setSearch(e.target.value);
};
return (
<div className="App">
<div className="inputContainer">
<input className="searchInput" type="text" onChange={handleChange} />
</div>
<h1>
{" "}
{weatherData.name} ,{" "}
{weatherData.sys ? <span>{weatherData.sys.country}</span> : ""}{" "}
</h1>
</div>
);
}
export default App;
this should be working fine just make sure to change : const APIKEY = "pass your api key "; to const APIKEY = "<your API key> ";
this is a demo in codesandbox
Create a promise function:
const getWeatherData = async () => {
try {
const weatherData = await axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${search}&appid={APIKEY}`);
console.log(weatherData.response);
if (weatherData.response.data) {
setWeatherData(weatherData.response.data);
}
} catch (err) {
console.error(err);
}
}
Then call it.
My React component loads infinitely and I want it to load only depending on the data that I get from the database, the console.log("1") is only for testing how many times the component loads.
This is the component:
import React from "react";
import Axios from "axios";
import { useState, useEffect } from "react";
function Added() {
const [data, setData] = useState([]);
useEffect(() => {
Axios.get("http://localhost:3001/").then((result) => {
setData(result.data);
});
}, [data]);
console.log("1");
return data.map((item) => {
return (
<div key={item._id}>
<h1>{item.finame}</h1>
<h1>{item.laname}</h1>
<h5>{item.age}</h5>
</div>
);
});
}
export default Added;
This is where it loads:
import "./App.css";
import { useState, useReducer, useEffect } from "react";
import Added from "./added";
import Axios from "axios";
function App() {
const GettingALlTheData = () => {
return Axios.get("http://localhost:3001/").then((result) => {
return result.data;
});
};
/* -------------------- For the useReducer -------------------- */
const Actions = {
Add: "add",
};
const defaultState = {
list: [GettingALlTheData],
};
console.log(defaultState);
const reducer = (state, action) => {
switch (action.type) {
case Actions.Add:
const listItem = action.payload;
try {
Axios.post("http://localhost:3001/add", listItem);
} catch (error) {
console.log(error + "444444");
}
return { ...state, list: [...state.list, listItem] };
default:
console.log("this is the default");
}
};
const [state, dispatch] = useReducer(reducer, defaultState);
/* ---------------------------- For the form ---------------------------- */
const [listItem, setListItem] = useState({ finame: "", laname: "", age: 0 });
const [list, setList] = useState([]);
useEffect(() => {
Axios.get("http://localhost:3001/").then((result) => {
state.list = result.data;
});
}, [state.list]);
const handelChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setListItem({ ...listItem, [name]: value });
};
const handelSubmit = (e) => {
e.preventDefault();
dispatch({ type: Actions.Add, payload: listItem });
};
const [data, setData] = useState({});
/* -------- for the useEffect to get the Data from the server -------- */
/* ------------------------ for the form return ---------------------- */
return (
<div className="App">
<h1>CRUD app using MERN stack</h1>
<form onSubmit={handelSubmit}>
<label htmlFor="finame">First name:</label>
<input
type="text"
name="finame"
id="finame"
value={listItem.finame}
onChange={handelChange}
/>
<label htmlFor="laname">Last name:</label>
<input
type="text"
name="laname"
id="laname"
value={listItem.laname}
onChange={handelChange}
/>
<label htmlFor="age">Age:</label>
<input
type="Number"
name="age"
id="age"
value={listItem.age}
onChange={handelChange}
/>
<button type="Submit">Submit</button>
</form>
{state.list ? (
<Added />
) : (
state.list.map((listItem) => {
return (
<div key={listItem._id}>
<h1>First name : {listItem.finame}</h1>
<h1>Last name: {listItem.laname}</h1>
<h3>Age: {listItem.age}</h3>
</div>
);
})
)}
</div>
);
}
export default App;
That's because you use the useEffect function with no dependency, so it is executed every time any prop/state changes (it's like a class component's componentDidUpdate).
I suggest you use it inside your Added component like a componentDidMount, so that it only execute once. To do it, you have to pass an empty dependency array, like so:
useEffect(() => {
//fetching the data
}, []);
I'm trying to implement debounce in a small/test React application.
It's just an application that fetch data from an API and it has a text field for an auto complete.
import React, { useEffect, useState, useMemo } from 'react';
import axios from 'axios';
const API = 'https://jsonplaceholder.typicode.com/posts';
const AutoComplete2 = () => {
const [ text, setText ] = useState("")
const [ posts, setPosts ] = useState([])
useEffect(() => {
async function fetchData() {
const data = await axios.get(API);
if(parseInt(data.status) !== 200) return;
setPosts(data.data)
}
fetchData();
}, [])
const handleTextChange = (event) => setText(event.target.value);
const handleSelectOption = (str) => setText(str);
const showOptions = useMemo(() => {
if(text === '') return;
const showPosts = [...posts].filter((ele) => ele.title.toLowerCase().includes(text.toLowerCase()));
if(showPosts.length === 1) {
setText(showPosts[0].title);
} else {
return (
<div>
{showPosts.map((obj, index) => {
return (
<div key={index} >
<span onClick={() => handleSelectOption(obj.title)} style={{cursor: 'pointer'}}>
{obj.title}
</span>
</div>
)
})}
</div>
)
}
}, [text, posts])
// addding debounce
const debounce = (fn, delay) => {
let timer;
return function() {
let context = this;
let args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(context, args)
}, delay);
}
}
const newHandleTextChange = ((val) => debounce(handleTextChange(val), 5000));
return (
<div>
<input type="text" value={text} onChange={newHandleTextChange} />
{showOptions}
</div>
)
}
export default AutoComplete2;
The application works, but not the debounce. I add a 5 seconds wait to clearly see if it is working, but every time I change the input text, it calls the function without the delay. Does anyone know why it is happening?
Thanks
A more idiomatic approach to debouncing in React is to use a useEffect hook and store the debounced text as a different stateful variable. You can then run your filter on whatever that variable is.
import React, { useEffect, useState, useMemo } from "react";
import axios from "axios";
const API = "https://jsonplaceholder.typicode.com/posts";
const AutoComplete2 = () => {
const [text, setText] = useState("");
const [debouncedText, setDebouncedText] = useState("");
const [posts, setPosts] = useState([]);
useEffect(() => {
async function fetchData() {
const data = await axios.get(API);
if (parseInt(data.status) !== 200) return;
setPosts(data.data);
}
fetchData();
}, []);
// This will do the debouncing
// "text" will always be current
// "debouncedText" will be debounced
useEffect(() => {
const timeout = setTimeout(() => {
setDebouncedText(text);
}, 5000);
// Cleanup function clears timeout
return () => {
clearTimeout(timeout);
};
}, [text]);
const handleTextChange = (event) => setText(event.target.value);
const handleSelectOption = (str) => setText(str);
const showOptions = useMemo(() => {
if (debouncedText === "") return;
const showPosts = [...posts].filter((ele) =>
ele.title.toLowerCase().includes(debouncedText.toLowerCase())
);
if (showPosts.length === 1) {
setText(showPosts[0].title);
} else {
return (
<div>
{showPosts.map((obj, index) => {
return (
<div key={index}>
<span
onClick={() => handleSelectOption(obj.title)}
style={{ cursor: "pointer" }}
>
{obj.title}
</span>
</div>
);
})}
</div>
);
}
}, [debouncedText, posts]);
return (
<div>
<input type="text" value={text} onChange={handleTextChange} />
{showOptions}
</div>
);
};
export default AutoComplete2;
import { useEffect, useState, useRef } from "react";
import axios from "axios";
import { backend_base_url } from "../constants/external_api";
export default function DebounceControlledInput() {
const [search_category_text, setSearchCategoryText] = useState("");
let debounceSearch = useRef();
useEffect(() => {
const debounce = function (fn, interval) {
let timer;
return function (search_key) {
clearTimeout(timer);
timer = setTimeout(() => {
fn(search_key);
}, interval);
};
};
const getCategories = function (search_key) {
axios
.get(`${backend_base_url}categories/${search_key}`)
.then((response) => {
console.log("API Success");
})
.catch((error) => {});
};
debounceSearch.current = debounce(getCategories, 300);
//use for initial load
//debounceSearch.current('');
}, []);
const searchCategory = (search_key) => {
debounceSearch.current(search_key);
};
return (
<form
className="form-inline col-4"
onSubmit={(e) => {
e.preventDefault();
}}
autoComplete="off"
>
<input
type="text"
placeholder=""
id="search"
value={search_category_text}
onChange={(e) => {
searchCategory(e.target.value);
setSearchCategoryText(e.target.value);
e.preventDefault();
}}
/>
</form>
);
}
I can't send message after subsequential clicks, if i click button at first time it is sending message to server, after that it is not sending messages to server.
import { useEffect, useState, useRef } from "react";
import Header from "../src/Components/Header";
import ChatHistory from "../src/Components/ChatHistory";
import ChatArea from "../src/Components/ChatArea";
function App() {
const [messages, setMessages] = useState([]);
const testValue = { messages, setMessages };
const socket = useRef(null);
const renderCount = useRef(0);
const sendMessage = (msg = "test") => {
if (socket.current) {
socket.current.send(msg);
}
addMessages(msg);
};
const addMessages = (msg) => {
setMessages((prev) => [...prev, msg]);
};
useEffect(() => {
socket.current = new WebSocket("ws://localhost:8001/ws");
socket.current.onmessage = (msg) => {
addMessages(msg);
};
}, []);
useEffect(() => {
return () => {
if (socket.current) {
socket.current.close();
}
};
}, [socket]);
console.log("i am rendering");
return (
<>
<Header />
<ChatHistory chatHistory={messages.current} />
<div>
<button onClick={sendMessage}>Send</button>
</div>
</>
);
}
export default App;
Above mentioned one is my code, While clicking send button at first time, it is triggering message to server, after another subsequential clicks it isn't triggering message to server. Help needed.
Your second useEffect actually closing the connection after the first render, it's unnecessary.
Moreover you don't really need to save your socket instance in a ref, usually you need a single instance:
const socket = new WebSocket("ws://localhost:8001/ws");
function App() {
const [messages, setMessages] = useState([]);
const addMessages = (msg) => {
setMessages((prev) => [...prev, msg]);
};
const sendMessage = (msg = "test") => {
socket.send(msg);
addMessages(msg);
};
// Setup
useEffect(() => {
socket.current.onmessage = addMessages;
}, []);
// Runs on App unmount, means on closing the application
useEffect(() => {
return () => {
socket.close();
};
}, []);
return (
<>
<Header />
<ChatHistory chatHistory={messages.current} />
<div>
<button onClick={sendMessage}>Send</button>
</div>
</>
);
}
useEffect(() => {
return () => {
if (socket.current) {
socket.current.close();
}
};
}, [socket]);
everytime the socket is changing, you close it
try to unmont in the same useEffect that is defining socket
useEffect(() => {
if (!socket.current) {
socket.current = new WebSocket("ws://localhost:8001/ws");
socket.current.onmessage = (msg) => {
addMessages(msg);
};
}
return () => {
if (socket.current) {
socket.current.close();
}
};
}, [socket]);
Note useRef is not optimal for that case, use useState instead
This is working, but i am not sure what i am did wrong.
import { useEffect, useRef, useState } from "react";
import Header from "./Components/Header";
import ChatHistory from "./Components/ChatHistory";
function App() {
const [chatHistory, setChatHistory] = useState([]);
const [isOnline, setIsOnline] = useState(false);
const [textValue, setTextValue] = useState("");
const webSocket = useRef(null);
webSocket.current = new WebSocket("ws://localhost:8001/ws");
useEffect(() => {
setTimeout(() => {
if (webSocket.current.readyState === WebSocket.OPEN) {
setIsOnline(true);
}
if (webSocket.current.readyState === WebSocket.CLOSED) {
setIsOnline(false);
setChatHistory([]);
}
}, 5);
}, [webSocket.current]);
const sendMessage = () => {
if (webSocket.current.readyState === WebSocket.OPEN) {
setChatHistory([...chatHistory, textValue]);
webSocket.current.send(textValue);
}
};
return (
<>
<div className="App">
<Header onLine={isOnline} />
<ChatHistory chatHistory={chatHistory} />
<input
type="text"
onChange={(e) => setTextValue(e.target.value)}
value={textValue}
placeholder="Type Message..."
/>
<button onClick={sendMessage}>Hit</button>
</div>
</>
);
}
export default App;
I am quite new to redux and react. I have also checked out a number of ways here to solve my problem but it appears I am not making any headway.
I intend performing an asynchronous operation using redux-thung following the tutorial https://github.com/reduxjs/redux-thunk, but the challenge I have is that the the function sendApplication() does not dispatch the action nextPage() neither does the function hitUrl() works. I have been on this issues for days. Someone should help me out please.
import React from 'react';
import { withStyles} from '#material-ui/styles';
import { FormLabel, TextField, Button } from '#material-ui/core';
import {connect} from 'react-redux';
import { nextPage, previousPage, enableBtnAvailability} from '../../actions/formPageController';
import { updateTextValueAvailability, clearField } from '../../actions/formInputController';
import { useStyles } from '../Styles/formStyles';
import { ValidatorForm, TextValidator} from 'react-material-ui-form-validator';
import sendApplication from '../../utility/sendRequest';
import { bindActionCreators } from 'redux';
const axios = require('axios');
const AvailablityTab= withStyles({
})((props) => {
console.log(props);
const handleChange=(e)=>{
const name= e.target.name;
const value = e.target.value;
const {updateTextValueAvailability} = props;
updateTextValueAvailability(name,value);
let unfilledFormFieldArray = props.text.filter((item)=> {
console.log(item);
return item.value=== "";
})
console.log(unfilledFormFieldArray);
console.log(unfilledFormFieldArray.length);
if(unfilledFormFieldArray.length ===0){
const {enableBtnAvailability} = props;
enableBtnAvailability();
}
}
const handleSubmit=()=>{
//const {postApplication} = props;
sendApplication();
console.log(props);
console.log('he submit');
}
const hitUrl = async function () {
//alert('hi')
try {
console.log(3);
const response = await axios.get('http://localhost:1337/api/v1/application/fetch-all');
console.log(response);
return response;
} catch (error) {
console.error(error);
}
};
const sendApplication = () => {
console.log(4);
console.log(props);
return function(props) {
console.log('xyz');
console.log(props);
const {nextPage} = props;
// dispatch(nextPage());
nextPage();
console.log(5);
alert('hi2')
return hitUrl().then(
() => {
console.log('thunk success');
nextPage();
},
() => {
console.log('thunk error');
//props.dispatch(previousPage())
},
);
};
}
const handlePrevious=()=>{
const {previousPage} = props;
previousPage();
}
console.log(props);
const classes = useStyles();
let validationRule = ['required'];
let errorMessages = ['This field is required'];
return (
<div className="formtab">
<ValidatorForm //ref="form"
onSubmit={handleSubmit}
onError={errors => console.log(errors)}
>
{props.text.map((each)=>{
let onFocus = false;
if(each.id === 1){
onFocus = true;
}
return(<div className={classes.question} key={each.id}>
<FormLabel className={classes.questionLabel} component="legend">{each.label}</FormLabel>
<TextValidator
id={"filled-hidden-label"}
className={classes.textField}
hiddenLabel
variant="outlined"
fullWidth
name={each.name}
onChange={handleChange}
value={each.value}
margin= "none"
placeholder={each.placeholder}
validators={validationRule}
errorMessages={errorMessages}
autoFocus= {onFocus}
/>
</div>)
})}
<div className={classes.buttondiv} >
<Button className={classes.prev} variant="contained" onClick={handlePrevious}>Previous</Button>
<Button className={classes.next} variant="contained" type="submit" disabled={!props.btnActivator} >Submit</Button>
</div>
</ValidatorForm>
</div>
)});
const mapStateToProps= (state)=>{
const availablity = state.availabilityQuestion;
return {
text: availablity.text,
radio: availablity.radio,
btnActivator: state.btnActivator.availability
}
}
const mapDispatchToProps = dispatch => bindActionCreators({
postApplication: sendApplication,
previousPage,
enableBtnAvailability,
updateTextValueAvailability,
nextPage,
clearField
}, dispatch)
export default connect(mapStateToProps, mapDispatchToProps)(AvailablityTab);
Since sendApplication returns a function, but does not execute it, you can call it like this:
sendApplication()(props); // it looks like you expect props to be passed to your function
This should successfully execute your nextPage function and return the value returned by hitUrl.
The alternative would be to execute the function instead of returning it
sendApplication(props);
...
const sendApplication = (props) => {
console.log('xyz');
console.log(props);
const {nextPage} = props;
// dispatch(nextPage());
nextPage();
console.log(5);
alert('hi2')
return hitUrl().then(
() => {
console.log('thunk success');
nextPage();
},
() => {
console.log('thunk error');
//props.dispatch(previousPage())
},
);
};
Now we've eliminated the internal function and just called it directly instead. Now calling sendApplication will return the return value of hitUrl.