how to set up on page load react - javascript

I am trying to log something to my console on page load in react. I've never really used react and I've only done node.js before, so this is new to me.
I have this so far, but it doesn't seem to be working. It seems more js then react.
window.onload(console.log("logging this here"))
how would I do this?
more code on page:
class NormalLoginForm extends React.Component {
state = {
error: null,
}
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (err) return
const email = this.props.form.getFieldValue('email')
const password = this.props.form.getFieldValue('password')
var accountStatus1 = ""
AuthorizationHome.doSignInWithEmailAndPassword(email, password)
.then(() => {
firebase.auth().onAuthStateChanged((user) => {
// window.onload(function (console.log("hello"))

For class component you can use;
ComponentDidMount(){
console.log("logging this here")
}
for functional components you can use;
useEffect(() => {
console.log("logging this here")
}, [])

it is impossible this way.
React component will render after window load event. So code will never trigger callback.
U need to change logic and just execute a callback if u want to call something in the component.
some example:
const ComponentWithAuth = () => {
const [user, setUser] = useState(null);
useEffect(() => {
getAuthUser().then(setUser)
});
if (user) {
return <PrivateComponent/>
}
return <LoginForm setUser={setUser}/>
}
const LoginForm = ({setUser) => {
const handleSubmit =async () => {
...
const user =await getAuthUser();
setUser(user);
}
...
}

Related

Dispatch outside component

I want to dispatch outside component. I want to use option 2 from this link [https://daveceddia.com/access-redux-store-outside-react/][1]. My code look like this
const loginUser = async (data) => {
return axios.get(url + "/sanctum/csrf-cookie").then(() => {
axios.post(url + '/api/login', data)
.then(res => {
return res.data
})
.catch((err) => {
console.log(err);
})
})
}
export const handleLogin = (data) => async (dispatch) => {
console.log('test');
try {
const user = await loginUser(data);
dispatch(actions.setUser(user));
} catch (err) {
console.log(err);
}
}
And into my component
const test = (e) => {
e.preventDefault;
handleLogin({email: 'test#test.pl', password: 'password'})
}
return (
<div className="container">
<h2>Login</h2>
<form onSubmit={handleSubmit(test)}>
//...
It doesn't finish code and it may contain mistakes but currently the most important for me is why this code doesn't work and if sometimes is wrong why doesn't show any error. I think that problem is in sync(dispatch). In this example I add console.log for test and it wasn't display. Without that function display console.log.
Redux thunk is added to the store too
const store = createStore(allReducers, composeWithDevTools(applyMiddleware(thunk)))
import store and use like this :
store.dispatch(actions.setUser(user));
and you can get state out of component with :
store.getState().items
you did not dispatch your actions in your component and in your action js .
you can call an action in component by props and dispatch and I could not see the props so I use useDispatch and call handleLogin action there.
use this in action.js file:
const user = await loginUser(data)(dispatch);
instead :
const user = await loginUser(data);
then in component:
import {useDispatch} from "react-redux";
const dispatch = useDispatch();
const test = (e) => {
e.preventDefault;
dispatch(handleLogin({email: 'test#test.pl', password: 'password'}))
}

How do I wrap methods in react components

I have a lot of functions looking like this
doSomething = async (...) => {
try {
this.setState({loading: true});
...
var result = await Backend.post(...);
...
this.setState({loading: false});
} catch(err) {
this.setState({error: err});
}
}
Basically I have 2 variables loading & error that I have to manage for a lot of functions and the code is basically the same for all of them. Since there are no decorators in javascript and I do not wish to install any experimental lib for that how could I wrap this function to remove the duplicated setStates from above ?
Here is my current way, I pass the function as parameter.
We have many API, fetch data form backend, we have to handle error and do something with data.
Only data of service are different, the handling error is the same.
private processServiceResponse(resp: any, doSthWithData: (data: any) => void) {
let { errors } = resp;
if (this.hasError(errors)) {
this.handleServiceErr(errors);
return;
}
let data = resp;
if (resp && resp.data) {
data = resp.data;
}
doSthWithData(data);
}
And here is how i pass function as parameter.
let rest1 = service1.getData();
processServiceResponse(rest1,(data)=>{
//only need to focus with processing data.
})
PS: It's typescript coding.
if you are using function conponents, you can define a custom hook to avoid repeat code
//useFetch.js
import { useState, useEffect } from 'react';
import axios from 'axios';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
setLoading('loading...')
setData(null);
setError(null);
const source = axios.CancelToken.source();
axios.get(url, { cancelToken: source.token })
.then(res => {
setLoading(false);
//checking for multiple responses for more flexibility
//with the url we send in.
res.data.content && setData(res.data.content);
res.content && setData(res.content);
})
.catch(err => {
setLoading(false)
setError('An error occurred. Awkward..')
})
return () => {
source.cancel();
}
}, [url])
return { data, loading, error }
export default useFetch;
usage:
import useFetch from './useFetch';
import './App.css';
function App() {
const { data: quote, loading, error } =
useFetch('https://api.quotable.io/random')
return (
<div className="App">
{ loading && <p>{loading}</p> }
{ quote && <p>"{quote}"</p> }
{ error && <p>{error}</p> }
</div>
);
}
export default App;
You can use a Higher Order Function (a function that takes as argument another function) to make the common loading and error functionality reusable. It is very similar to a decorator pattern. For example:
const doSomething = withLoadingAndErrorHandling(Backend.post, this.setState);
function withLoadingAndErrorHandling(fn, setState) {
return async function(...args) {
try {
setState({loading: true});
var result = await fn(args);
setState({loading: false});
return result;
} catch(err) {
setState({error: err});
}
}
}

Trouble dealing with setState async function equivalent with hooks

import React from "react";
import { UserContext } from "./../contexts";
import {
removeStoredAuthData,
storedAuthIsValid,
storeNewAuthData,
} from "./../utils/auth";
import { getUserInfos } from "./../api/userAuthentication";
class UserProvider extends React.Component {
constructor(props) {
super(props);
this.state = {
user: "",
};
}
render() {
return (
<UserContext.Provider
value={{
user: this.state.user,
clearUserProfile: () => {
const user = "";
removeStoredAuthData();
this.setState({ user });
},
saveUserProfile: (response) => {
const user = response.data;
storeNewAuthData(response);
this.setState({ user });
},
populateUserProfile: (displayLoader, hideLoader) => {
const storedToken = localStorage.getItem("appsante-token");
const storedId = localStorage.getItem("appsante-id");
if (storedAuthIsValid()) {
displayLoader(() => {
getUserInfos(storedId)
.then((response) => {
const user = { ...response.data, token: storedToken };
this.setState({ user }, hideLoader());
})
.catch((error) => console.log(error));
});
}
},
}}
>
{this.props.children}
</UserContext.Provider>
);
}
}
export default UserProvider;
Hi everyone !
I trying to convert a React class component into a function component, with hooks.
But I can't find a way to deal properly with that line :
this.setState({ user }, hideLoader());
Unlike setState in class components, useState doesn't take a callback as second parameter, and I can't find how to achieve it with useEffect.
Could anyone help me ? Thanks !
Because the loader's presence can't be determined from the value in / change in user alone, you'll need another state variable, maybe one that contains the callback - perhaps call it hideLoader. After getUserInfos resolves, call setHideLoader with the callback, so that a useEffect hook with that function as a dependency can see the change and call the callback:
const [hideLoader, setHideLoader] = useState();
useEffect(() => {
if (hideLoader) {
hideLoader(); // or, if this is a HOF: hideLoader()()
setHideLoader(); // callback done; remove callback from state
}
}, [hideLoader]);
// ...
populateUserProfile: (displayLoader, hideLoaderParam) => {
// ...
getUserInfos(storedId)
.then((response) => {
setUser({ ...response.data, token: storedToken }); // hook version
setHideLoader(hideLoaderParam);
})
and the rest of your code can be mostly the same - only call setHideLoader up above, inside getUserInfos.
I think you should do this :-
import React, { useState } from 'react';
const [user, setUser] = useState("");
populateUserProfile: async (displayLoader, hideLoader) => {
const storedToken = localStorage.getItem("appsante-token");
const storedId = localStorage.getItem("appsante-id");
if (storedAuthIsValid()) {
displayLoader();
let response = await getUserInfos(storedId)
const user = { ...response.data, token: storedToken };
setUser(user);
hideLoader();
};
}

Issues triggering Modal to show inside useEffect hook [duplicate]

I get this error:
Can't perform a React state update on an unmounted component. This is
a no-op, but it indicates a memory leak in your application. To fix,
cancel all subscriptions and asynchronous tasks in a useEffect cleanup
function.
when fetching of data is started and component was unmounted, but function is trying to update state of unmounted component.
What is the best way to solve this?
CodePen example.
default function Test() {
const [notSeenAmount, setNotSeenAmount] = useState(false)
useEffect(() => {
let timer = setInterval(updateNotSeenAmount, 2000)
return () => clearInterval(timer)
}, [])
async function updateNotSeenAmount() {
let data // here i fetch data
setNotSeenAmount(data) // here is problem. If component was unmounted, i get error.
}
async function anotherFunction() {
updateNotSeenAmount() //it can trigger update too
}
return <button onClick={updateNotSeenAmount}>Push me</button> //update can be triggered manually
}
The easiest solution is to use a local variable that keeps track of whether the component is mounted or not. This is a common pattern with the class based approach. Here is an example that implement it with hooks:
function Example() {
const [text, setText] = React.useState("waiting...");
React.useEffect(() => {
let isCancelled = false;
simulateSlowNetworkRequest().then(() => {
if (!isCancelled) {
setText("done!");
}
});
return () => {
isCancelled = true;
};
}, []);
return <h2>{text}</h2>;
}
Here is an alternative with useRef (see below). Note that with a list of dependencies this solution won't work. The value of the ref will stay true after the first render. In that case the first solution is more appropriate.
function Example() {
const isCancelled = React.useRef(false);
const [text, setText] = React.useState("waiting...");
React.useEffect(() => {
fetch();
return () => {
isCancelled.current = true;
};
}, []);
function fetch() {
simulateSlowNetworkRequest().then(() => {
if (!isCancelled.current) {
setText("done!");
}
});
}
return <h2>{text}</h2>;
}
You can find more information about this pattern inside this article. Here is an issue inside the React project on GitHub that showcase this solution.
If you are fetching data from axios(using hooks) and the error still occurs, just wrap the setter inside the condition
let isRendered = useRef(false);
useEffect(() => {
isRendered = true;
axios
.get("/sample/api")
.then(res => {
if (isRendered) {
setState(res.data);
}
return null;
})
.catch(err => console.log(err));
return () => {
isRendered = false;
};
}, []);
TL;DR
Here is a CodeSandBox example
The other answers work of course, I just wanted to share a solution I came up with.
I built this hook that works just like React's useState, but will only setState if the component is mounted. I find it more elegant because you don't have to mess arround with an isMounted variable in your component !
Installation :
npm install use-state-if-mounted
Usage :
const [count, setCount] = useStateIfMounted(0);
You can find more advanced documentation on the npm page of the hook.
Here is a simple solution for this. This warning is due to when we do some fetch request while that request is in the background (because some requests take some time.)and we navigate back from that screen then react cannot update the state. here is the example code for this. write this line before every state Update.
if(!isScreenMounted.current) return;
Here is Complete Example
import React , {useRef} from 'react'
import { Text,StatusBar,SafeAreaView,ScrollView, StyleSheet } from 'react-native'
import BASEURL from '../constants/BaseURL';
const SearchScreen = () => {
const isScreenMounted = useRef(true)
useEffect(() => {
return () => isScreenMounted.current = false
},[])
const ConvertFileSubmit = () => {
if(!isScreenMounted.current) return;
setUpLoading(true)
var formdata = new FormData();
var file = {
uri: `file://${route.params.selectedfiles[0].uri}`,
type:`${route.params.selectedfiles[0].minetype}`,
name:`${route.params.selectedfiles[0].displayname}`,
};
formdata.append("file",file);
fetch(`${BASEURL}/UploadFile`, {
method: 'POST',
body: formdata,
redirect: 'manual'
}).then(response => response.json())
.then(result => {
if(!isScreenMounted.current) return;
setUpLoading(false)
}).catch(error => {
console.log('error', error)
});
}
return(
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={styles.scrollView}>
<Text>Search Screen</Text>
</ScrollView>
</SafeAreaView>
</>
)
}
export default SearchScreen;
const styles = StyleSheet.create({
scrollView: {
backgroundColor:"red",
},
container:{
flex:1,
justifyContent:"center",
alignItems:"center"
}
})
This answer is not related to the specific question but I got the same Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function. and as a React newcomer could not find a solution to it.
My problem was related to useState in an unmounted component.
I noticed that I was calling a set state function (setIsLoading) after the function that unmounted my component:
const Login = () => {
const [isLoading, setIsLoading] = useState(false);
const handleLogin = () => {
setIsLoading(true);
firebase.auth().then(
functionToUnMountLoginSection();
// the problem is here
setIsLoading(false);
)
}
}
The correct way is to call setIsLoading when the component is still mounted, before calling the function to unmount/process user login in my specific case:
firebase.auth().then(
setIsLoading(false);
functionToUnMountLoginSection();
)
You add the state related datas into the useEffect body for not rerunning them every rerendering process. This method will solve the problem.
useEffect(() => {
let timer = setInterval(updateNotSeenAmount, 2000)
return () => clearInterval(timer)
}, [notSeenAmount])
REF: Tip: Optimizing Performance by Skipping Effects
Custom Hook Solution (ReactJs/NextJs)
Create a new folder named 'shared' and add two folders named 'hooks', 'utils' in it. Add a new file called 'commonFunctions.js' inside utils folder and add the code snippet below.
export const promisify = (fn) => {
return new Promise((resolve, reject) => {
fn
.then(response => resolve(response))
.catch(error => reject(error));
});
};
Add a new file called 'fetch-hook.js' inside hooks folder and add the code snippet below.
import { useCallback, useEffect, useRef } from "react";
import { promisify } from "../utils/commonFunctions";
export const useFetch = () => {
const isUnmounted = useRef(false);
useEffect(() => {
isUnmounted.current = false;
return () => {
isUnmounted.current = true;
};
}, []);
const call = useCallback((fn, onSuccess, onError = null) => {
promisify(fn).then(response => {
console.group('useFetch Hook response', response);
if (!isUnmounted.current) {
console.log('updating state..');
onSuccess(response.data);
}
else
console.log('aborted state update!');
console.groupEnd();
}).catch(error => {
console.log("useFetch Hook error", error);
if (!isUnmounted.current)
if (onError)
onError(error);
});
}, []);
return { call }
};
Folder Structure
Our custom hook is now ready. We use it in our component like below
const OurComponent = (props) => {
//..
const [subscriptions, setSubscriptions] = useState<any>([]);
//..
const { call } = useFetch();
// example method, change with your own
const getSubscriptions = useCallback(async () => {
call(
payment.companySubscriptions(userId), // example api call, change with your own
(data) => setSubscriptions(data),
);
}, [userId]);
//..
const updateSubscriptions = useCallback(async () => {
setTimeout(async () => {
await getSubscriptions();
}, 5000);// 5 seconds delay
}, [getSubscriptions]);
//..
}
In our component, we call 'updateSubscriptions' method. It will trigger 'getSubscriptions' method in which we used our custom hook. If we try to navigate to a different page after calling updateSubscriptions method before 5 seconds over, our custom hook will abort state update and prevent that warning on the title of this question
Wanna see opposite?
Change 'getSubscriptions' method with the one below
const getSubscriptions = useCallback(async () => {
const response = await payment.companySubscriptions(userId);
setSubscriptions(response);
}, [userId]);
Now try to call 'updateSubscriptions' method and navigate to a different page before 5 seconds over
Try this custom hook:
import { useEffect, useRef } from 'react';
export const useIsMounted = () => {
const isMounted = useRef(false);
useEffect(() => {
isMounted.current = true;
return () => (isMounted.current = false);
}, []);
return isMounted;
};
function Example() {
const isMounted = useIsMounted();
const [text, setText] = useState();
const safeSetState = useCallback((callback, ...args) => {
if (isMounted.current) {
callback(...args);
}
}, []);
useEffect(() => {
safeSetState(setText, 'Hello')
});
}, []);
return <h2>{text}</h2>;
}

How to update the state value using setTimeout in React Hooks?

Am trying to reset the state value after some time using setTimeout function.
const SetTimeout = props => {
let [errorText, setError] = useState(
props.errorMessage ? props.errorMessage : ""
);
useEffect(() => {
if (errorText !== "") {
setTimeout(() => {
setError("");
}, 4000);
} else {
// console.log("no error")
}
}, [errorText]);
return <div>{errorText}</div>;
};
const MapStateToProps = state => {
return {
errorMessage: state.errorReducer.error
};
};
Am getting the errorMessage from an api call, after some time i'm trying to make that message to empty using useState.
But the component is getting re-rendered with the same error message. could you please help me in fixing this?
You are mixing component state and redux state here which is pretty bad and why you are seeing this behaviour.
You are initially rendering the component with the error message from within Redux, and passing this into the component as a property value. The component displays this, set's it's own state value. After the timeout runs, it's updating it's own state, which causes a re-render, and the Redux value is again passed into the component via the properties.
I would suggest you forget about using useState and use a Redux action to clear the error message that it is storing.
you are using redux to not use state in react components and here you are using state in your component. so what you can do is to add the erromessage to your global state :
state ={
...,
errormessage:undefined
}
and then in your action you need to change your state.errormessage like this:
export const show_error = message => {
return {
type: "SHOW_ERROR",
payload: message
};
};
export const remove_error = () => {
return {
type:"REMOVE_ERROR"
};
};
imagine calling post api to add post using redux thunk you can do it like this:
export function add_post(data) {
return function(dispatch) {
return axios
.post('/posts', data)
.then(res => {
dispatch(fetch_posts_data());})
.catch(err => dispatch(
show_error(err)
);
setTimeout(function() {
dispatch(remove_error());
}, 2000););
};
}
in your reducer :
case "SHOW_ERROR":
return {
...state,
posts: { ...state.posts, errormessage: action.message}
};
case "REMOVE_ERROR":
return {
...state,
posts: { ...state.posts, errormessage: undefined }
};
now to retrieve the errormessage in your component you can use normal connect method but here i will use redux hooks useSelector():
const Error = ()=>{
const errormessage = useSelector(state=>state.errormessage)
return(
<>
{
errormessage?
<div>{errormessage}</div>
:""
}
</>
)
}
I've just found this out! So it may not be perfect.
Hooks have a useSelector and a useDispatch (from react-redux)
To stick with having your error in Redux, you component would look like this:
const SetTimeout = () => {
const errorText = useSelector(state => state.errorReducer.error);
const clearError = useDispatch();
useEffect(() => {
if (errorText !== "") {
const timeout = setTimeout(() => {
clearError({ type: "CLEAR_ERROR" });
}, 5000);
} else {
// console.log("no error")
}
// this will clear Timeout when component unmounts like in willComponentUnmount
return () => { clearTimeout(timeout); };
}, []);
return <div style={{ color: "red" }}>{errorText}</div>;
};
export default SetTimeout;
Pretty cool functional component without the redux boiler plate code.
Hope that helps

Categories