Maximum update depth exceeded. After Login Using Context And Hooks - reactjs

I'm using hooks and Context when after login my URL refreshing sometimes and get this Error Maximum update depth exceeded and my page not loading when refresh page everything is Ok!
this code my Login Page :
function LoginView(props) {
const classes = useStyles()
const [Username, setUsername] = useState('');
const [Password, setPassword] = useState('');
const { getUserLogin, isLogin } = useContext(UserContext)
const handelSubmit = (e) => {
console.log(Username, Password)
if (Username.length < 1) {
alert("لطفا نام کاربری را وارد نمایید")
if (Password.length < 1) {
alert("لطفا رمز عبور را واردنمایید")
}
}
let uuid = uuidv1()
console.log(uuid)
localStorage.setItem('myUUID', uuid)
let xml = 'exampel xlm (srver is SOAP)';
console.log(xml)
getUserLogin(xml)
}
useEffect(() => {
if (isLogin) {
props.history.push("/MainPage")
}
})
return (
<div style={{ direction: 'rtl', }}>
<MyLogo />
<div className={classes.root} >
<div className='textfiled'>
<TextField
className={classes.txt}
name='username'
inputProps={{ style: { textAlign: 'center' } }}
onChange={(e) => setUsername(e.target.value)}
placeholder='نام کاربری' ></TextField>
</div>
<div >
<TextField
className={classes.txt}
inputProps={{ style: { textAlign: 'center' } }}
name='password'
type='password'
onChange={(e) => setPassword(e.target.value)}
placeholder='رمز عبور' ></TextField>
</div>
<div>
<Button color={'inherit'} className={classes.btn} onClick={() => handelSubmit()} > ورود</Button>
</div>
</div>
</div>
)
}
export default withRouter(LoginView);
after submitting my cod get some error in console google I read this post
Maximum update depth exceeded
and change my onclick function but steel error Maximum update depth exceeded
and this is my Context :
export const UserContext = createContext()
export const UserContextDispacher = createContext();
const UserProvider = (props) => {
const [user, setUser] = useState({ username: '', password: '', })
const [isLogin, setisLogin] = useState(false)
const getUserLogin = (value) => {
axios.post('https://exampel.com/myexampel.asmx', value, { headers: { 'Content-Type': 'text/xml;charset=UTF-8' } }).then(function (response) {
// console.log(response)
var options = {
attributeNamePrefix: "#_",
attrNodeName: "attr", //default is 'false'
textNodeName: "#text",
ignoreAttributes: true,
ignoreNameSpace: false,
allowBooleanAttributes: false,
parseNodeValue: true,
parseAttributeValue: false,
trimValues: true,
cdataTagName: "__cdata", //default is 'false'
cdataPositionChar: "\\c",
localeRange: "", //To support non english character in tag/attribute values.
parseTrueNumberOnly: false,
attrValueProcessor: a => he.decode(a, { isAttributeValue: true }),//default is a=>a
tagValueProcessor: a => he.decode(a) //default is a=>a
};
// Intermediate obj
var tObj = parser.getTraversalObj(response.data, options);
var jsonObj = parser.convertToJson(tObj, options);
//set Token
var token = jsonObj["soap:Envelope"]["soap:Body"].AuthenticateUserResponse.Token
var authResult = jsonObj["soap:Envelope"]["soap:Body"].AuthenticateUserResponse.AuthenticateUserResult
if (authResult != false) {
localStorage.setItem('mytoken', token)
localStorage.setItem('myisLogin', authResult)
setisLogin(true)
} else {
localStorage.setItem('myisLogin', authResult)
setisLogin(false)
}
return authResult
}).catch(function (error) {
// console.log("erorr in send to login : " + error)
})
}
return (
<UserContext.Provider value={{ user, getUserLogin, isLogin }}>
<UserContextDispacher.Provider>
{props.children}
</UserContextDispacher.Provider>
</UserContext.Provider>
)
}
export default withRouter(UserProvider);
how to fix it this error?
thank for helping me
UPDATE
if (authResult != false) {
localStorage.setItem('mytoken', token)
localStorage.setItem('myisLogin', authResult)
setisLogin(true)
props.history.push("/MainPage");
}
and delete useEffect from loginview.js

useEffect runs every time a change occurs so useEffect is getting triggered infinitely many times so the error.
Solution : Use isLogin as dependency for useEffect.
useEffect(() => {
if (isLogin) {
props.history.push("/MainPage")
}
},[isLogin])

Related

Is assigned a value but never used

My code keeps bringing torusPlugin is assigned a value but never used, LoggedInView is assigned a value but never used and I don't know where I went wrong. I have checked the code and the torusPlugin function was used, same with the loggedInView.
import { useEffect, useState } from "react";
import { Card, Form } from "react-bootstrap";
import { FaComment, FaRecycle, FaRetweet, FaThumbsUp } from "react-icons/fa";
import { Web3AuthCore } from "#web3auth/core";
import {
WALLET_ADAPTERS,
CHAIN_NAMESPACES,
SafeEventEmitterProvider,
} from "#web3auth/base";
import { OpenloginAdapter } from "#web3auth/openlogin-adapter";
import { TorusWalletConnectorPlugin } from "#web3auth/torus-wallet-connector-plugin";
import Twitter from "./twitter";
import RPC from "./evm";
import { APP_CONSTANTS } from "./constants";
import "./App.css";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
const clientId = APP_CONSTANTS.CLIENT_ID; // get from https://dashboard.web3auth.io
function App() {
const [web3auth, setWeb3auth] = useState<Web3AuthCore | null>(null);
const [provider, setProvider] = useState<SafeEventEmitterProvider | null>(
null
);
const [tweets, setTweets] = useState<Array<any> | null>(null);
const [comment, setComment] = useState<string | "">("");
const [userName, setUserName] = useState<string | "">("");
const [profileImage, setProfileImage] = useState<string | "">("");
const [newTweetName, setNewTweetName] = useState<string | "">("");
const [newTweetDescription, setNewTweetDescription] = useState<string | "">(
""
);
const refreshTime = APP_CONSTANTS.REACT_APP_REFRESH_TIMER * 1000
const [torusPlugin, setTorusPlugin] =
useState<TorusWalletConnectorPlugin | null>(null);
useEffect(() => {
const init = async () => {
try {
const web3auth = new Web3AuthCore({
clientId,
chainConfig: {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: "0x13881",
rpcTarget: APP_CONSTANTS.RPC_TARGET, // This is the mainnet RPC we have added, please pass on your own endpoint while creating an app
},
});
const openloginAdapter = new OpenloginAdapter({
adapterSettings: {
clientId,
network: "testnet",
uxMode: "popup",
whiteLabel: {
name: "Twitter DApp",
logoLight: APP_CONSTANTS.APP_LOGO,
logoDark: APP_CONSTANTS.APP_LOGO,
defaultLanguage: "en",
dark: true, // whether to enable dark mode. defaultValue: false
},
loginConfig: {
// Add login configs corresponding to the providers on modal
// Twitter login
jwt: {
name: "Custom Auth Login",
verifier: APP_CONSTANTS.ADAPTER_TWITTER_CLIENT_VERIFIER, // Please create a verifier on the developer dashboard and pass the name here
typeOfLogin: "twitter", // Pass on the login provider of the verifier you've created
clientId: APP_CONSTANTS.ADAPTER_TWITTER_CLIENT_ID, // Pass on the clientId of the login provider here - Please note this differs from the Web3Auth ClientID. This is the JWT Client ID
},
// Add other login providers here
},
},
});
const torusPlugin = new TorusWalletConnectorPlugin({
torusWalletOpts: {},
walletInitOptions: {
whiteLabel: {
theme: { isDark: true, colors: { primary: "#ffffff" } },
logoDark:
"https://i.ibb.co/kDNCfC9/reshot-icon-wallet-9-H3-QMSDLFR.png",
logoLight:
"https://i.ibb.co/kDNCfC9/reshot-icon-wallet-9-H3-QMSDLFR.png",
},
useWalletConnect: true,
enableLogging: true,
},
});
await web3auth.addPlugin(torusPlugin);
setTorusPlugin(torusPlugin);
await web3auth.configureAdapter(openloginAdapter);
setWeb3auth(web3auth);
await web3auth.init();
if (web3auth.provider) {
await setProvider(web3auth.provider);
let user = await web3auth.getUserInfo();
console.log('user ', user)
if(user.name && user.name !== null && user.name !== " " && user.name !== "")
setUserName(user.name)
if(user.profileImage && user.profileImage !== null && user.profileImage !== " " && user.profileImage !== "")
setProfileImage(user.profileImage)
}
await fetchAllTweets();
//eslint-disable-next-line react-hooks/exhaustive-deps
} catch (error) {
console.error(error);
}
};
init();
}, []);
const logout = async () => {
if (!web3auth) {
console.log("web3auth not initialized yet");
return;
}
await web3auth.logout();
setProvider(null);
};
const login = async () => {
if (!web3auth) {
console.log("web3auth not initialized yet");
return;
}
const web3authProvider = await web3auth.connectTo(
WALLET_ADAPTERS.OPENLOGIN,
{
loginProvider: "jwt",
extraLoginOptions: {
domain: APP_CONSTANTS.AUTH0_DOMAIN, // Please append "https://" before your domain
verifierIdField: "sub",
},
}
);
setProvider(web3authProvider);
if(web3authProvider){
let user = await web3auth.getUserInfo();
if(user.name && user.name !== null && user.name !== " " && user.name !== "")
setUserName(user.name)
if(user.profileImage && user.profileImage !== null && user.profileImage !== " " && user.profileImage !== "")
setProfileImage(user.profileImage)
}
};
/*
const getAccounts = async () => {
if (!provider) {
console.log("provider not initialized yet");
return;
}
const rpc = new RPC(provider);
const userAccount = await rpc.getAccounts();
return userAccount;
};
*/
const refresh = (e: any) => {
e.preventDefault();
fetchAllTweets();
};
const fetchAllTweets = async () => {
console.log("fetchalltweetsrunning");
if (!provider) {
console.log("provider not initialized yet");
return;
}
const rpc = new RPC(provider);
try {
let fetchedTweets = await rpc.getAllTweets();
let tweets = [...fetchedTweets];
setTweets(tweets.reverse());
} catch (error) {
console.log("error in fetching tweets", error);
}
};
const upVote = async (tweetIndex: any) => {
if (!provider) {
console.log("provider not initialized yet");
return;
}
try {
const rpc = new RPC(provider);
await rpc.sendUpVoteTransaction(tweetIndex);
fetchAllTweets();
} catch (error) {
console.log("failed to execute upvote transaction", error);
}
};
const addNewTweet = (e: any) => {
e.preventDefault();
if (!provider) {
console.log("provider not initialized yet");
return;
}
try {
const rpc = new RPC(provider);
toast.success("Tweet added successfully", {
position: toast.POSITION.TOP_CENTER,
});
rpc.sendWriteTweetTransaction(newTweetName, newTweetDescription);
setTimeout(function () {
fetchAllTweets();
}, refreshTime);
fetchAllTweets();
} catch (error) {
toast.error("Something went wrong", {
position: toast.POSITION.TOP_LEFT,
});
console.log("failed to execute new tweet transaction", error);
}
};
const addComment = async (event: any, tweetIndex: any) => {
event.preventDefault();
if (!provider) {
console.log("provider not initialized yet");
return;
}
try {
const rpc = new RPC(provider);
toast.success("Comment added successfully - refresh after 30 sec", {
position: toast.POSITION.TOP_CENTER,
});
await rpc.sendAddCommentTransaction(tweetIndex, comment);
fetchAllTweets();
} catch (error) {
toast.error("Something went wrong", {
position: toast.POSITION.TOP_LEFT,
});
console.log("failed to execute add comment transaction", error);
}
};
// Event handlers
const handleCommentChange = async (event: any) => {
setComment(event.target.value);
};
const handleNewTweetNameChange = async (event: any) => {
setNewTweetName(event.target.value);
};
const handleNewTweetDescriptionChange = async (event: any) => {
setNewTweetDescription(event.target.value);
};
const loggedInView = (
<>
<button className="button" onClick={logout}>
Logout
</button>
<div>
<h1>New Tweet</h1>
<Card>
<Card.Body>
<Card.Title>What are you thinking? Tweet it out!</Card.Title>
<Card.Text></Card.Text>
<Form.Control
as="input"
onChange={handleNewTweetNameChange}
placeholder="Tweet Name"
/>
<br></br>
<br></br>
<Form.Control
as="textarea"
onChange={handleNewTweetDescriptionChange}
placeholder="Description"
/>
<br></br>
<FaRetweet onClick={addNewTweet} />
</Card.Body>
</Card>
</div>
<div>
<h1>
All Tweets <FaRecycle onClick={fetchAllTweets} />
</h1>
{(tweets || []).map((tweet: any, i) => (
<div key={i}>
<div>
<Card>
<Card.Body>
<Card.Title>
<FaThumbsUp onClick={(event) => upVote(i)} /> {tweet.name}
</Card.Title>
<p>Total Upvotes: {tweet.upvotes}</p>
<p>Tweeted by: {tweet.fromAddress}</p>
<Card.Text>{tweet.description}</Card.Text>
<div>
<h3>All Comments</h3>
{tweet.comments.map((comment: any, j: any) => (
<div key={j}>
Comment {j + 1}: {comment}
</div>
))}
<h3>New Comment</h3>
<span>
<Form.Control
as="input"
onChange={handleCommentChange}
placeholder="Your comment..."
/>
</span>
<span>
<FaComment onClick={(event) => addComment(event, i)} />
</span>
</div>
</Card.Body>
<a
href={
APP_CONSTANTS.OPENSEA_ASSETS_URL +
"/" +
APP_CONSTANTS.CONTRACT_ADDRESS +
"/" +
i
}
rel="opener"
>
Buy Now
</a>
</Card>
</div>
</div>
))}
</div>
<div></div>
<div id="console" style={{ whiteSpace: "pre-line" }}>
<p style={{ whiteSpace: "pre-line" }}></p>
</div>
</>
);
const unloggedInView = (
<>
<div className="login-account">
<button className="twitter-bg btn" onClick={login}>
<img src="images/twitter-white.png" alt=""></img>
Login to your Twitter account
</button>
</div>
</>
);
return (
<div className="grid">
{provider ? (
<Twitter
logoutButton={logout}
handleNewTweetDescriptionChange={handleNewTweetDescriptionChange}
handleNewTweetNameChange={handleNewTweetNameChange}
addNewTweet={addNewTweet}
fetchAllTweets={fetchAllTweets}
tweets={tweets}
upVote={upVote}
handleCommentChange={handleCommentChange}
addComment={addComment}
refresh={refresh}
username={userName}
profileimage={profileImage}
/>
) : (
unloggedInView
)}{" "}
<ToastContainer />
</div>
// <div className="grid">{provider
// ? loggedInView
// : unloggedInView}</div>
// {/* <div className="grid">{loggedInView}</div> */}
);
}
export default App;
enter image description here
this is a screenshot of my code terminal
You are actually not using torusPlugin (line 38 screenshot) anywhere. Inside your useEffect you created a new const torusPlugin and then you are calling that const instead of the [torusPlugin, ...] state you declared on line 38 of the screenshot. Try to differentiate your variables / constants names otherwise would be difficult for you to identify mistakes.

Options not showing when using custom input in React-Bootstrap-TypeAhead

I am using React-Bootstrap-TypeAhead's latest version in my React project. The main goal is to display the options menu when the user types. The menu is displayed when using the default input component but once I use the render input method for customization the options menu stops showing:
working example
import React, { useState } from 'react';
import { AsyncTypeahead } from 'react-bootstrap-typeahead';
/* example-start */
const BasicExample = ({ key, label }) => {
const [singleSelections, setSingleSelections] = useState([]);
const [multiSelections, setMultiSelections] = useState([]);
const [query, setQuery] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [options, setOptions] = useState([]);
const PER_PAGE = 50;
const SEARCH_URI = 'https://api.github.com/search/users';
function makeAndHandleRequest(query, page = 1) {
return fetch(`${SEARCH_URI}?q=${query}+in:login&page=${page}&per_page=50`)
.then((resp) => resp.json())
.then(({ items, total_count }) => {
/* eslint-disable-line camelcase */
const options = items.map((i) => ({
avatar_url: i.avatar_url,
id: i.id,
login: i.login,
}));
return { options, total_count };
})
.catch((err) => console.log(err));
}
const _handleInputChange = (query) => {
setQuery(query);
};
const _handlePagination = (e, shownResults) => {
const { query } = this.state;
const cachedQuery = this._cache[query];
// Don't make another request if:
// - the cached results exceed the shown results
// - we've already fetched all possible results
if (cachedQuery.options.length > shownResults || cachedQuery.options.length === cachedQuery.total_count) {
return;
}
setIsLoading(true);
const page = cachedQuery.page + 1;
makeAndHandleRequest(query, page).then((resp) => {
const options = cachedQuery.options.concat(resp.options);
// this._cache[query] = { ...cachedQuery, options, page };
setIsLoading(false);
setOptions(options);
});
};
const _handleSearch = (query) => {
setIsLoading(true);
makeAndHandleRequest(query).then((resp) => {
setIsLoading(true);
setOptions(resp?.options || []);
});
};
return (
<>
<AsyncTypeahead
{...{ query, isLoading, options }}
id="async-pagination-example"
labelKey="login"
maxResults={PER_PAGE - 1}
minLength={2}
onInputChange={_handleInputChange}
onPaginate={_handlePagination}
onSearch={_handleSearch}
renderInput={({ inputRef, referenceElementRef, ...inputProps }) => (
<div className="form-group h-64">
<label>Job Category</label>
<div className="input-group">
<input
type="text"
{...inputProps}
ref={(input) => {
inputRef(input);
// referenceElementRef(input);
}}
className="form-control"
placeholder=""
/>
</div>
</div>
)}
paginate
placeholder="Search for a Github user..."
renderMenuItemChildren={(option) => (
<div key={option.id}>
<img
alt={option.login}
src={option.avatar_url}
style={{
height: '24px',
marginRight: '10px',
width: '24px',
}}
/>
<span>{option.login}</span>
</div>
)}
useCache={false}
/>
</>
);
};
/* example-end */
export default BasicExample;
The reason you're not seeing any results rendered is that _handleInputChange is triggering a re-render and resetting the debounced onSearch handler before it can fire.
You can wrap _handleSearch with useCallback to fix that:
const _handleSearch = useCallback((query) => {
setIsLoading(true);
makeAndHandleRequest(query).then((resp) => {
setIsLoading(false);
setOptions(resp?.options || []);
});
}, []);

Cannot display GET method to modify and update data with formData

I am training with ReactJS and NodeJS and trying to update a form. The POST method works, I use Multer and formData but I have a problem with the PUT/GET method to modify the data. In fact, PUT works, I can modify the data unlike the GET which displays [object Object]. I don't know where it can come from. You can see a screenshoot and the code, I use Material UI.
import useRequest from "../../../customHooks/useRequest";
const CreateCustomer = ({ className, ...rest }) => {
const [name, setName] = useState("");
const [description, setDescription] = useState("");
const [chosePicture, setChosePicture] = useState([]);
const classes = useStyles();
const handleChangeName = (e) => {
setName(e.target.value); };
const handleChangeDescription = (e) => {
setDescription(e.target.value); };
const { uuid } = useParams();
const toasterSucc = () => {
return (
toast.success('Customer successfully created!', {
position: "bottom-center",
autoClose: 4000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined
})
); };
const toasterErr = (error) => {
return (
toast.error(`${error}`, {
position: "bottom-center",
autoClose: 4000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined
})
); };
const updateSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("cust_main_name", name);
formData.append("cust_details", description);
formData.append("avatar", chosePicture);
console.log(chosePicture);
try {
await axios.put(`http://xxx/customers/${uuid}`, formData);
toasterSucc();
} catch (er) {
er.response && toasterErr(er.response.data);
} };
const { data } = useRequest("get", `http://xxx/customers/${uuid}`);
useEffect(() => {
if (data[0]) {
setName(data[0]);
setDescription(data[0]);
setChosePicture(data[0]);
} }, [data]);
return (
<Fragment>
<Grid>
<Paper className={classes.mainTable}>
<form className={classes.editForm} encType="multipart/form-data" method="post" autoComplete="off">
<input
className={classes.btnfile}
type="file"
id="file"
name="avatar"
onChange={(e) => {
setChosePicture(e.target.files[0]);
}}
/>
<TextField
className={classes.inputField}
label="Name"
type="text"
name="name"
value={name}
onChange={handleChangeName}
placeholder="Enter a name"
variant="outlined"
fullWidth
InputLabelProps={{
shrink: true,
}}
/>
<TextField
className={classes.inputField}
label="Description"
type="text"
name="description"
value={description}
onChange={handleChangeDescription}
placeholder="Enter a description"
fullWidth
InputLabelProps={{
shrink: true,
}}
variant="outlined"
/>
</form>
</Paper>
</Grid>
<div className={classes.btnContainer}>
<Button onClick={updateSubmit} type="submit" className={classes.button}>Save</Button>
<ToastContainer />
</div>
</Fragment> ); };
export default CreateCustomer;
The code for useRequest :
const useRequest = (method, url, option) => {
const [data, setData] = useState([]);
const [error, setError] = useState("");
useEffect(() => {
let isSubscribe = true;
const fetchData = async () => {
try {
const result = await Axios[method](url);
if (isSubscribe) {
setData(result.data);
}
} catch (err) {
if (isSubscribe) {
setError(err);
setData([]);
}
}
};
if (isSubscribe) {
fetchData();
}
return () => {
isSubscribe = false;
};
}, [url, method, option]);
return { data, error };
};
export default useRequest;
You are returning an object with properties data and error.
return { data, error };
It means that when you fetch it in client side, you will fetch object with both sub-objects. You should console.log(data ) after fetching it and check the result.
const { data } = useRequest("get", `http://xxx/customers/${uuid}`)
You should extract only data sub-object and it will probably have name and description properties.

Upload File to firebase storage and get URL to save in a database in react

I have react with redux app and Asp.NetCorewebApi as Back-end . I want to upload file to firebase storage and get its URL to save in a database table so that I can display it.
The file is uploaded successfully but it does not setUrl to save in state.
here is relevant part of UploadMaterial.jsx component when input file is selected.
// component state variables
const[image,setImage]=useState(null);
const[url,setUrl]=useState('');
const[fileName,setFileName]=useState('');
// handlechange function when file is selected
const handleChange = e => {
const image = document.getElementById("uploadFile").files[0];
setFileName(image.name); //set filename
setImage(image); // set file
const uploadTask = storage.ref(`courseMaterial/${fileName}/`).put(image);
uploadTask.on('state_changed',
(snapshot) => {
// progress function ....
const progress = Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
setProgress({ progress });
},
(error) => {
console.log(error);
},
);
() => {
// complete function ....
storage.ref(`courseMaterial`).child(`${fileName}`).getDownloadURL().then(url => {
setUrl(url);
console.log(url); // why url is not updated?
}) , (error) => {
// error function ....
console.log(error);
}
}
}
the file uploaded successfully but the URL is not updated so I am unable to save in state to send to my back-end database. Thanks in advance for help.
update:
here is the console.log and info screenshots.
[
here is the whole component UploadMaterial.jsx
import React, { useState, useEffect } from "react";
import { Grid, TextField, withStyles, FormControl, InputLabel, Select, MenuItem, Button, FormHelperText } from "#material-ui/core";
import {useForm} from "../../_helpers";
import {storage} from '../../firebase';
import { useDispatch } from "react-redux";
import * as actions from "../../_actions/materialActions";
import { useToasts } from "react-toast-notifications";
import { Link,useParams,useHistory,useLocation } from 'react-router-dom';
import LinearProgress from '#material-ui/core/LinearProgress';
const styles = theme => ({
formControl: {
margin: theme.spacing(1),
minWidth: 300,
},
smMargin: {
margin: theme.spacing(1)
}
})
const initialFieldValues = {
title: '',
description: '',
postedBy: '',
userName: '',
courseId: '',
courseTitle: '',
type: '',
fileTitle: ''
};
const UploadMaterial = ({ classes, ...props }) => {
const[image,setImage]=useState(null);
const[url,setUrl]=useState('');
const[fileName,setFileName]=useState('');
const[preview ,setPreview]=useState(null);
const[progress,setProgress]=useState(0);
const dispatch = useDispatch();
//
function useQuery() {
return new URLSearchParams(useLocation().search);
}
let query = useQuery();
// let {fullName}=useParams();
let courseId=query.get("courseId");
let courseTitle=query.get("courseTitle");
let history = useHistory()
//
const { addToast } = useToasts();
//material-ui select
const inputLabel = React.useRef(null);
const [labelWidth, setLabelWidth] = React.useState(0);
React.useEffect(() => {
setLabelWidth(inputLabel.current.offsetWidth);
}, []);
//
const user=JSON.parse(localStorage.getItem('user'))
const handleChange = e => {
const image = document.getElementById("uploadFile").files[0];
setFileName(courseId+"-"+image.name);
setImage(image);
// setFileTitle(temp)
setPreview(e.target.files[0])
const uploadTask = storage.ref(`courseMaterial/${fileName}/`).put(image);
uploadTask.on('state_changed',
(snapshot) => {
// progrss function ....
const progress = Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
setProgress({ progress });
},
(error) => {
// error function ....
addToast(" some error !check file size/type ", { appearance: 'error' })
console.log(error);
},
);
() => {
// complete function ....
storage.ref(`courseMaterial`).child(fileName).getDownloadURL().then(url => {
setUrl(url);
}) , (error) => {
// error function ....
console.log(error);
}
}
}
console.log("url:",url);
console.log("fileName:",fileName);
//validate()
//validate({title:'jenny'})
const validate = (fieldValues = values) => {
let temp = { ...errors }
if ('title' in fieldValues)
temp.title = fieldValues.title ? "" : "This field is required."
if ('type' in fieldValues)
temp.type = fieldValues.type ? "" : "This field is required."
if ('description' in fieldValues)
temp.description = fieldValues.description ? "" : "This field is required."
setErrors({
...temp
})
if (fieldValues == values)
return Object.values(temp).every(x => x == "")
}
const {
values,
setValues,
errors,
setErrors,
handleInputChange,
resetForm
} = useForm(initialFieldValues, validate)
///
useEffect(()=>{
setValues( { ...values, postedBy:user.id,userName:user.username,
courseId: courseId,courseTitle: courseTitle,
fileTitle:url})
},[values.title])
// for tinymce editor
console.log("values:",values);
//console.log("url:", url);
const onSuccess = () => {
resetForm()
addToast("uploaded successfully", { appearance: 'success' })
}
const handleSubmit = e => {
e.preventDefault()
if (validate()) {
addToast("working please wait !", { appearance: 'warning' })
// file upload code here
if(progress==100)
dispatch(actions.create(values, onSuccess))
}
}
console.log("progress:",progress);
return (
<form autoComplete="off" noValidate className={classes.root} onSubmit={handleSubmit}>
<hr/>
<input id="uploadFile" type="file" className={classes.formControl} onChange={handleChange}/><br/>
<br/><LinearProgress value={progress} color="primary" max="100" /><br/>
<TextField
placeholder="Enter Title in short"
name="title"
variant="outlined"
label="title"
value={values.title}
onChange={handleInputChange}
{...(errors.title && { error: true, helperText: errors.title })}
/>
<br/>
<FormControl variant="outlined"
className={classes.formControl}
{...(errors.type && { error: true })}
>
<InputLabel ref={inputLabel}>Material type</InputLabel>
<Select
name="type"
value={values.type}
onChange={handleInputChange}
labelWidth={labelWidth}
>
<MenuItem value="">Select type</MenuItem>
<MenuItem value="helpingfile">Helping File</MenuItem>
<MenuItem value="instructionfile">Instruction file</MenuItem>
</Select>
{errors.type && <FormHelperText>{errors.type}</FormHelperText>}
</FormControl><br/>
<TextField
placeholder="Enter short description"
name="description"
variant="outlined"
label="Description"
value={values.description}
onChange={handleInputChange}
{...(errors.description && { error: true, helperText: errors.description })}
/><br/>
<div>
<Button
variant="contained"
color="primary"
type="submit"
className={classes.smMargin}
>
Submit
</Button>
<Button
variant="contained"
className={classes.smMargin}
onClick={resetForm}
>
Reset
</Button>
<Button onClick={() => history.goBack()}
size="small" className={classes.smMargin} variant="contained" color="secondary">
back
</Button>
</div>
</form>
);
}
export default (withStyles(styles)(UploadMaterial));
Cleaning up the indentation of your code, you notice the following problems:
uploadTask.on('state_changed',
(snapshot) => {
// progress function ....
const progress = Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
setProgress({ progress });
},
(error) => {
console.log(error);
},
); // PROBLEM: this bracket & semi-colon closes off on()
() => { // <-- which means this function is floating and never actually called
// complete function ....
storage.ref(`courseMaterial`).child(`${fileName}`).getDownloadURL()
.then(url => {
setUrl(url);
console.log(url); // why url is not updated?
}), // PROBLEM: this comma is outside of then()
(error) => { // <-- meaning this error function is also floating and never called
// error function ....
console.log(error);
}
}
Fixing it, you get:
uploadTask.on('state_changed',
(snapshot) => {
// file upload progress report
const progress = Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
setProgress({ progress });
},
(error) => {
// file upload failed
console.log(error);
},
() => {
// file upload completed
storage.ref(`courseMaterial`).child(`${fileName}`).getDownloadURL()
.then(
(url) => {
// got download URL
setUrl(url);
console.log(url);
},
(error) => {
// failed to get download URL
console.log(error);
}
);
}
);
You can avoid this in the future using a StorageObserver instead of the three callback arguments to on().
This line:
on(firebase.storage.TaskEvent.STATE_CHANGED, nextCallback, errorCallback, completeCallback)
can be converted to:
on(firebase.storage.TaskEvent.STATE_CHANGED, {
next: nextCallback,
error: errorCallback,
complete: completeCallback
})
Which can be used like so:
uploadTask.on('state_changed', {
next(snapshot): {
// file upload progress report
const progress = Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
setProgress({ progress });
},
error(error): {
// file upload failed
console.log(error);
},
complete(): {
// file upload completed
storage.ref(`courseMaterial`).child(`${fileName}`).getDownloadURL()
.then(
(url) => {
// got download URL
setUrl(url);
console.log(url);
},
(error) => {
// failed to get download URL
console.log(error);
}
);
}
});
Make sure you are useing useEffect hook as it is working asynchronous
Here is my code :
const [imageUpload, setImageUpload] = React.useState(null); // image selecting state
const [image, setImage] = React.useState(""); //url setting state
const storage = getStorage();
useEffect(() => {
// declare the data getImage function
const getImage = async () => {
const ImageURL = await getDownloadURL(ref(storage, `${imageUpload.name}`));
setImage(ImageURL);
}
// call the function
getImage()
console.log(image)
}, [imageUpload])
const uploadImage = () => {
if (imageUpload == null) return;
const storageRef = ref(storage, `${imageUpload.name}`);
uploadBytes(storageRef, imageUpload).then((snapshot) => {
console.log("Uploaded image");
});
};

Why Next.js does not accept passed function as function?

In ReactJs it works well.
import React, { useState, useEffect } from "react";
import { Snackbar } from "#material-ui/core";
import axios from "axios";
import { withTranslation } from "../../i18n";
import MuiAlert from "#material-ui/lab/Alert";
import sha512 from "crypto-js/sha512";
import { LoginEmailIn, LoginEmailOut } from "../../Types";
import { getTempUserUuid } from "../../util/Utility";
//import ReactPixel from "react-facebook-pixel";
import styles from "../../styles/LoginAndRegistration.module.css";
import {BEUrl} from "../../util/Utility"
function Alert(props: any) {
return <MuiAlert elevation={6} variant="filled" {...props} />;
}
function LoginWithEmail({ t },props: {
eventId: string;
trackUserInteractions:boolean;
eventName: string;
setLogin: (a:boolean)=> void;
}) {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [alertOpen, setAlertOpen] = useState(false);
const [alertMessage, setAlertMessage] = useState("");
const [alertType, setAlertType] = useState("error");
const alertClose = (event: any, reason: any) => {
if (reason === "clickaway") {
return;
}
setAlertOpen(false);
};
const checkEmail = () => {
const regex = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (email === "") {
setAlertType("error");
setAlertMessage(t("Please enter your registered e-mail address"));
setAlertOpen(true);
return false;
} else if (!regex.test(email)) {
setAlertType("error");
setAlertMessage(t("The entered e-mail address is not valid"));
setAlertOpen(true);
return false;
} else return true;
};
const checkPassword = () => {
if (password === "") {
setAlertType("error");
setAlertMessage(t("Please enter your password"));
setAlertOpen(true);
return false;
} else return true;
};
const loginButtonPressed = () => {
if (checkEmail() && checkPassword()) {
const loginData: LoginEmailIn = {
email: email,
passwordHash: sha512(password).toString(),
tempUserId: getTempUserUuid(),
};
let url = BEUrl + "loginEmail";
axios({
method: "post",
url: url,
data: loginData,
headers: { "Content-Type": "application/json", crossDomain: true },
})
.then((resp: any) => {
const data: LoginEmailOut = resp.data;
if (!data.error) {
setAlertType("success");
setAlertMessage(t(`Successful login, Welcome ${data.userName!}`));
setAlertOpen(true);
localStorage.setItem("isRegistrationHappened", "true");
localStorage.setItem("userNameLoggedIn", data.userName!);
localStorage.setItem("jwt", data.jwt!);
setTimeout(function () {
window.location.reload();
}, 1200);
} else {
setAlertType("error");
setAlertMessage(t(`${data.error}`));
setAlertOpen(true);
}
})
.catch((error) => console.error(error));
}
};
/*const trackEmailLoginFinished = () => {
if (useClientSide) {
if (
window.location.hostname !== "localhost" &&
props.trackUserInteractions &&
!userInteractions.includes(`IA ${props.eventName} EmailLoginFinished`)
) {
ReactPixel.track(`IA ${props.eventName} EmailLoginFinished`, {
content_ids: [props.eventId],
});
userInteractions.push(`IA ${props.eventName} EmailLoginFinished`);
localStorage.setItem(
"userInteractions",
JSON.stringify([...userInteractions])
);
}
}
};*/
const [userInteractions, setUserInteractions] = useState();
useEffect(()=> {
setUserInteractions(JSON.parse(
localStorage.getItem("userInteractions") ?? "[]"
))
},[])
return (
<>
<div className={styles.loginContainer}>
<label className={styles.loginInputLabel}>{`${t(
"Please enter your e-mail address"
)}`}</label>
<input
id="loginMail"
name="loginMail"
className="loginInput toLowerCase"
autoFocus
type="email"
onChange={(event) => setEmail(event.target.value.toLowerCase())}
/>
</div>
<label className="loginInputLabel">{`${t(
"Please enter your password"
)}`}</label>
<input
id="loginPassword"
className="loginInput"
name="loginPassword"
type="password"
onChange={(event) => setPassword(event.target.value)}
/>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
}}
>
<button
className="loginAndRegButton"
onClick={() => {
loginButtonPressed();
/*trackEmailLoginFinished();*/
}}
>
{t("Login")}
</button>
<p style={{ margin: 0 }} className="loginOrRegSwitch">
{t("You don't have an account yet")}?{" "}
<a href="#" onClick={() => props.setLogin(false)}>
{" "}
{t("Sign up")}
</a>
</p>
</div>
<Snackbar open={alertOpen} autoHideDuration={3000} onClose={alertClose}>
<Alert onClose={alertClose} severity={alertType}>
{alertMessage}
</Alert>
</Snackbar>
</>
);
}
export default withTranslation("translate")<any>(LoginWithEmail);
I think it has to be:
function LoginWithEmail({ t, ...props }) { /* ... */ }

Resources