using componentWillUnmount in context of next js - reactjs

I'm trying to run a method on componentWillUnmount(i'm using the next js framework).The issue is that the componentWillUnmount method does not fire. However componentDidMount is working fine.
class TeamMember extends Component {
constructor(props)
{
super(props);
this.state = {
teamMember: this.props.teamMember,
startDate: null,
}
}
static async getInitialProps ( context ) {
const { slug } = context.query;
const res = await fetch(``);
const teamMember = await res.json();
return {
teamMember:teamMember
}
}
async componentDidMount()
{
this.setState({
startDate: Date.now()
})
Tracker.pushObjectToStorage('profilesViewed',{
title:this.state.teamMember[0].title.rendered,
id:this.state.teamMember[0].id
})
}
async componentWillUnmount(props)
{
alert("ddffff");
console.log("ddsds");
}
}
this is my code for the page. when you leave the page I want the componentWillUnmount to fire. i've put an alert there for test purposes.

This is expected and intended behavior of Nextjs routing. For more information, you can check this issue: https://github.com/zeit/next.js/issues/2819.
When you go to another page, no unmounting of components occurs, but instead, a whole new page is rendered.
This is the same behaviour as if you were refreshing (or landing for the first time) on a page. A React component will not unmount when you hit F5 on a page, because it is not unmounting, the page is simply refreshing.

Related

how to work reusable state in class components?

do class components support Reusable State in React 18? I wrote an example
componentDidMount() {
console.log("componentDidMount");
if (!this.mounted) {
this.fetchData();
this.mounted = true;
}
}
fetchData() {
fetch().then((data) => {
this.setState((statePrev) => {
console.log("prev data", statePrev); // always null after editing the file of this component and triggering Fast Refresh, how to work reusable state in class components?
return {
data: [
...(Array.isArray(statePrev?.data) ? statePrev?.data : []),
...data
]
};
});
});
}
I expected that when I edit and save the component file and React Refresh is triggered then statePrev will contain the previous state but it is always null
second problem is when React Refresh is triggered, the this.mounted property also does not work to determine that the mounting has occurred and you do not need to run fetch again

Component did update works only after second click

My code adds a new item in the firebase databse when i click a button, then i want the list of objects in my page to automatically update, because i don't want to manualy reload the page. So i came up with this code
constructor(props){
super(props);
this.state = {
groups: [],
code:'',
name:'',
update:true
}
}
async fetchGroups (id){
fetchGroupsFirebase(id).then((res) => {this.setState({groups:res})})
};
async componentDidUpdate(prevProps,prevState){
if(this.state.update !== prevState.update){
await this.fetchGroups(this.props.user.id);
}
}
handleCreateSubmit = async event => {
event.preventDefault();
const{name} = this.state;
try{
firestore.collection("groups").add({
title:name,
owner:this.props.user.id
})
.then((ref) => {
firestore.collection("user-group").add({
idGroup:ref.id,
idUser:this.props.user.id
});
});
this.setState({update: !this.state.update});
}catch(error){
console.error(error);
}
What i was thinking, after i add the new item in firebase, i change the state.update variable, which triggers componentDidUpdate, which calls the new fetching.
I tried calling the fetchGroups function in the submit function, but that didn't work either.
What am i doing wrong and how could i fix it?
ComponentDidUpdate will not be called on initial render. You can either additionally use componentDidMount or replace the class component with a functional component and use the hook useEffect instead.
Regarding useEffect, this could be your effect:
useEffect(() => {
await this.fetchGroups(this.props.user.id);
}, [update]);
Since you can't use useEffect in class components so you would need to rewrite it as functional and replace your this.state with useState.

Why won't my changes to state show in my componentDidMount lifecycle?

I am building an app using React and for my homepage, I set state in the componentDidMount lifecycle:
export default class HomePage extends Component {
state = {
posts: [],
token: '',
};
//Display posts when homepage renders
componentDidMount() {
//If token exists, run lifecycle event
if (this.props.location.state.token) {
this.setState({ token: this.props.location.state.token });
}
Axios.get('http://localhost:3000/api/posts/all')
.then((req) => {
this.setState({ posts: req.data });
})
.catch((err) => {
console.log(err.message);
throw err;
});
console.log(this.state);
}
However when I run the console log at the end of the lifecycle method, it shows posts and token as still being empty. I know they are being populated because the posts from the req.data show up in my JSX. Why does it show state being empty when I console log inside the method?
React setState is asynchronous!
React does not guarantee that the state changes are applied immediately.
setState() does not always immediately update the component.
Think of setState() as a request rather than an immediate command to update the component.
this.setState((previousState, currentProps) => {
return { ...previousState, foo: currentProps.bar };
});

How do I access axios response promise and use it on my webpage?

How do I gain acceess to promises so that I can use for example the bitcoin price on my website?
axios.get('https://api.coinmarketcap.com/v1/ticker/?convert=EUR&limit=10')
.then(function(response){
console.log(response.data[0].price_usd);
});
Here is a codepen with a sample of the code.
https://codepen.io/albin996/pen/LzLZYX?editors=1112
We should start by noting that external requests should be carefully handled in React so the actual reactivity works well keeping its performance. That's why we're going to create a class to holds this logic in a organized way.
const URL = 'https://api.coinmarketcap.com/v1/ticker/convert=EUR&limit=10';
// Our component now is a full class
class BitcoinDisplay extends React.Component {
constructor(props) {
super(props);
// Start with no response available
this.state = {response: false};
}
// Waits the component to be rendered before calling API
componentDidMount() {
axios.get(URL).then(response => {
// Updates the state with the response
this.setState({ response })
});
}
// Renders the component with the available data
render() {
if(!this.state.response) {
// Show a loading state because data may not be available yet
return 'Loading data...';
} else {
return (<h1>{response.data[0].price_usd}</h1>);
}
}
}
Then, you render it inside the DOM.
ReactDOM.render(BitcoinDisplay, document.getElementById('app'));

Update route and redux state data at same time

I have an app that has user profiles. On the user profile there are a list of friends, and when clicking on a friend it should take you to that other user profile.
Currently, when I click to navigate to the other profile (through redux-router Link) it updates the URL but does not update the profile or render the new route.
Here is a simplified code snippet, I've taken out a lot of code for simplicity sake. There are some more layers underneath but the problem happens at the top layer in my Profile Container. If I can get the userId prop to update for ProfileSections then everything will propagate through.
class Profile extends Component {
componentWillMount() {
const { userId } = this.props.params
if (userId) { this.props.getUser(userId) }
}
render() {
return <ProfileSections userId={user.id} />
}
}
const mapStateToProps = ({ user }) => {
return { user }
}
export default connect(mapStateToProps, { getUser })(Profile);
As you can see, what happens is that I am running the getUser action on componentWillMount, which will happen only once and is the reason the route changes but the profile data does not update.
When I change it to another lifecycle hook like componentWillUpdate to run the getUser action, I get in an endless loop of requests because it will keep updating the state and then update component.
I've also tried using the onEnter hook supplied by react-router on Route component but it doesn't fire when navigating from one profile to another since it's the same route, so that won't work.
I believe I'm thinking about this in the wrong way and am looking for some guidance on how I could handle this situation of navigating from one profile to another while the data is stored in the redux store.
So I would suggest you approach this in the following way:
class Profile extends Component {
componentWillMount() {
const { userId } = this.props.params
if (userId) {
// This is the initial fetch for your first user.
this.fetchUserData(userId)
}
}
componentWillReceiveProps(nextProps) {
const { userId } = this.props.params
const { userId: nextUserId } = nextProps.params
if (nextUserId && nextUserId !== userId) {
// This will refetch if the user ID changes.
this.fetchUserData(nextUserId)
}
}
fetchUserData(userId) {
this.props.getUser(userId)
}
render() {
const { user } = this.props
return <ProfileSections userId={user.id} />
}
}
const mapStateToProps = ({ user }) => {
return { user }
}
export default connect(mapStateToProps, { getUser })(Profile);
Note that I have it set up so in the componentWillMount lifecycle method, you make the request for the initial userId. The code in the componentWillReceiveProps method checks to see if a new user ID has been received (which will happen when you navigate to a different profile) and re-fetches the data if so.
You may consider using componentDidMount and componentDidUpdate instead of componentWillMount and componentWillReceiveProps respectively for the fetchUserData calls, but it could depend on your use case.

Resources