React Hook useState Constructor with Asyncstorage - reactjs

I am trying to set the initial state with asyncstorage. Is there a way to do this?
const _retrieveUser = async () => {
return await AsyncStorage.getItem('authUser');
}
const [user, setUser] = useState(_retrieveUser().then(user => user) || null);

The initial value will have to be something that's synchronously available. Then you can do your async work in an effect. If necessary, you can render a placeholder while this work is in progress
const [user, setUser] = useState(null);
useEffect(() => {
_retrieveUser().then(setUser);
}, []);
if (user === null) {
return <div>Loading...</div>
} else {
// return the real component
}

you can pass a function inside useState method to manage the initial state in another simple way:
const [user, setUser] = useState(async () => {
const data = await AsyncStorage.getItem('authUser') //get data and store them in constat
setUser(data || null) //here the state set self
}
);

Related

UseEffect not filling all states

SO this is my code, i'm trying to filter my offers by there users , i have called all my offers and all my user and there states are full but when i try to filter offers by there users the state stay empty but when i hit spacebar on my keyboard the state get full like it's the spacebar is triggering useEffect to fill the state
const [offer, setOffer] = useState([]);
const [user, setUser] = useState({});
const[useroffers,setUseroffer]=useState([]);
const isOffer = async () => {
const oflg = await GetAllOff();
setOffer(oflg);
};
const isLoggedIn = async () => {
const userLg = await CurrentUser();
setUser(userLg.data.user);
};
const isUseroffer = async()=>{
setUseroffer(offer.filter((el)=>el.createdbyId === user._id));
};
useEffect( () => {
isOffer();
isLoggedIn();
isUseroffer();
}, []);
console.log(offer);
console.log(user)
console.log(useroffers);
So useEffect is filling the offers and user States but not filling the useroffers state intil i click on the spacebar
useroffers is dependent on both user and offer but you are trying to set it in the same render cycle as those two. Updated state values aren't available until the render cycle after they are set, so setUseroffers doesn't have access to the values it needs to update properly. To solve this you can declare a second useEffect which is dependent on user and offer so that as those values update so does your filtered array.
const [offer, setOffer] = useState([]);
const [user, setUser] = useState({});
const [useroffers, setUseroffer] = useState([]);
const isOffer = async () => {
const oflg = await GetAllOff();
setOffer(oflg);
};
const isLoggedIn = async () => {
const userLg = await CurrentUser();
setUser(userLg.data.user);
};
useEffect(() => {
isOffer();
isLoggedIn();
}, []);
useEffect(() => {
setUseroffer(offer.filter((el) => el.createdbyId === user._id));
}, [user, offer]);
codesandbox
Alternatively you can do it all in a single useEffect by awaiting the offer and user values and using them directly to set all three states once they are available. (This will result in only a single rerender rather than the possible four in the previous example)
const [offer, setOffer] = useState([]);
const [user, setUser] = useState({});
const [useroffers, setUseroffer] = useState([]);
useEffect(() => {
const login = async () => {
const userLg = await CurrentUser();
const ofLg = await GetAllOff();
setUser(userLg.data.user);
setOffer(ofLg);
setUseroffer(
ofLg.filter((el) => el.createdbyId === userLg.data.user._id)
);
};
login();
}, []);
codesandbox

When using the useEffect hook, the method of using a dependency array is confusing

I've been studying react hook lately. I found the following in the book I saw.
It is said that the fetchAndSetUser function is updated only when the userId is changed using the useCallback hook.
function Profile({ userId }) {
const [user, setUser] = useState();
const fetchAndSetUser = useCallback(
async needDetail => {
const data = await fetchUser(userId, needDetail);
setUser(data);
},
[userId]
);
useEffect(() => {
fetchAndSetUser(false);
} , [fetchAndSetUser]);
// ...
However, if the fetchAndSetUser function is updated only when the userId is changed using the useCallback hook, I wonder what the difference is from just putting the userId in the dependency array in the useEffect hook. (There is a code below.)
function Profile({ userId }) {
const [user, setUser] = useState();
const fetchAndSetUser = async ( needDetail ) => {
const data = await fetchUser(userId, needDetail);
setUser(data);
};
useEffect(() => {
fetchAndSetUser(false);
} , [userId]);
// ...
I wonder if the two codes are the same or if they are different.
Even though I think both codes would achieve the same result, there is a small difference.
If you wanted to pass that fetchAndSetUser (with no useCallback) function to the children, any time Profile component updated it would also update the children.
You can always combine all with:
function Profile({ userId }) {
const [user, setUser] = useState();
const fetchAndSetUser = useCallback(async ( needDetail ) => {
const data = await fetchUser(userId, needDetail);
setUser(data);
}, [userId]);
useEffect(() => {
fetchAndSetUser(false);
} , [userId]);

How to ignore previous async effects when useEffect is called again?

I have a simple component that makes an async request when some state changes:
const MyComp = () => {
const [state, setState] = useState();
const [result, setResult] = useState();
useEffect(() => {
fetchResult(state).then(setResult);
}, [state]);
return (
<div>{result}</div>
);
};
The problem is, sometimes the state changes twice in a short lapse of time, and the fetchResult function can take a very different amount of time to resolve according to the state value, so sometimes this happens:
As you can guess, as state now is state2 and not state1 anymore, I would like result to be result2, ignoring the response received in the then of the -obsolete- first effect call.
Is there any clean way to do so?
I would suggest you setup some kind of request cancellation method in the useEffect cleanup function.
For example with axios, it looks like that:
const MyComp = () => {
const [state, setState] = useState();
const [result, setResult] = useState();
useEffect(() => {
const source = axios.CancelToken.source();
fetchResult({state, cancelToken: source.cancelToken }).then(setResult);
return () => {
source.cancel()
}
}, [state]);
return (
<div>{result}</div>
);
};
You have a similar API with fetch called AbortController
What this will do is it will cancel the stale requests if your state changed so only the last one will resolve (and set result).
I've not tested this... but my initial thought would be if you have the state in the response, you could check if the state fetched matches the current state. If not, then the state has changed since the request and you no longer care about the response so don't set it.
useEffect(() => {
fetchResult(state).then((response) => {
response.state === state ? setResult(response.data) : false;
});
}, [state]);
You might also be able to do it by keeping a record of the fetchedState on each request.. and again discard it if it no longer matches.
useEffect(() => {
let fetchedState = state;
fetchResult(fetchedState).then((response) => {
fetchedState === state ? setResult(response) : false;
});
}, [state]);
I've built something like the below in order to only ever use the last result of the last request sent:
const REQUEST_INTERVAL = 2000
const MyComponent = () => {
const [inputState, setInputState] = useState();
const [result, setResult = useState()
const requestIndex = useRef(0)
useEffect(() => {
const thisEffectsRequestIndex = requestIndex.current + 1
requestIndex.current = thisEffectsRequestIndex
setTimeout(() => {
if(thisEffectsRequestIndex === requestIndex.current) {
fetch('http://example.com/movies.json')
.then((response) => {
if(thisEffectsRequestIndex === requestIndex.current) {
setResult(response.json())
}
})
}
})
, REQUEST_INTERVAL)
}, [inputState])
return <div>{result}</div>
}

How to convert Firebase Auth Class Component Lifecycle to Hooks useEffect in ReactJS?

im trying to convert the following class component's firebase auth lifecycle to hooks' useEffect method.
class App extends React.Component {
state = {
user: null
};
unsubscribeFromAuth = null;
componentDidMount(){
this.unsubscribeFromAuth = firebase.auth().onAuthStateChanged((user) => {
this.setState({user: user});
});
}
componentWillUnmount(){
this.unsubscribeFromAuth();
}
}
I tried to convert it with the following code, it seems to work but i'm not sure if it is the right implementation. There is a warning that says 'user' is assigned a value but never used. Should i change line 2 to: $const [ , setUser] = useState(null);
const App = () => {
const [user, setUser] = useState(null);
const unsubscribeFromAuth = useRef(null);
useEffect(() => {
unsubscribeFromAuth.current = auth.onAuthStateChanged((user) => {
setUser(user);
console.log(user);
})
return () => {
unsubscribeFromAuth();
}
}, []);
}
Create a custom hook to return the authenticated user.
This hook can be reused in any functional component needing the authenticated user info.
function useAuthUser(props) {
const [user, setUser] = useState(null);
useEffect(() => {
// no need for ref here
const unsubscribeFromAuth = auth.onAuthStateChanged((user) => {
setUser(user);
})
return () => {
unsubscribeFromAuth();
}
}, []);
return user; // return authenticated user
}
function App() {
const user = useAuthUser(someProps);
return <div>{user}</div>
}

How to fetch initial value using useState() before the component is mounted

The variables in the Context are initialized using useState(function) which gets a value when the function returns a value. This value is then accessed by components of the applications. The problem here is that the component is mounted and then the data is fetched instead I want it to fetch the data before the component is rendered.
My Context store
function AuthContextProvider(props){
var s;
const fetchData=()=> {
userSession.getFile('st.json')
.then((file) => {
s= JSON.parse(file || "")
setState(s
)
})
return s
}
const [userType,setState]=useState(s)
index.js
function Auth () {
const {userType} =useContext(AuthContext)
const auth=()=>{
if (userSession.isSignInPending()) {
userSession.handlePendingSignIn()
.then((response) => {
if({userType}==="Hire"){window.location.href = "/dashboard";}
else if({userType}==="Dev"){
window.location.href = "/dashboard";
}
else{
window.location.href = "/profilef";
}
});
}
}
return null;
Here the condition is executed and then the data is fetched from useState()
instead I want it to fetch the data and then execute the conditions
Use async await & useEffect
Inittialized userType as '' (empty string)
function AuthContextProvider(props) {
const [userType, setState] = useState('');
useEffect(() => {
async function fetchData() {
const file = await userSession.getFile('st.json');
const s = JSON.parse(file || "");
setState(s);
}
fetchData();
},[]);
return userType;
}

Resources