How can I implement componentDidMount and componentDidUpdate using the useEffect hook? - react-hooks

Please how can I implement exactly this code if I use the useEffect hook in a functional component?
componentDidUpdate(prevProps) {
if (this.props.user.id !== prevProps.user.id) {
this.setState({
isLoggedIn: true,
});
}
}
componentDidMount() {
this.props.fetchConversations();
}

const {fetchConverstaions, user} = props
useEffect(() => {
fetchConverstaions()
}, [])
useEffect(() => {
setIsLoggedIn(true) //useState
}, [user?.id])
The useEffect with empty dependencies [] will only run once, hence, componentDidMount. The second useEffect will run whenever user.id changes in value.

From the React documentation - Using the Effect Hook
Tip
If you’re familiar with React class lifecycle methods, you can think of >useEffect Hook as componentDidMount, componentDidUpdate, and ?>componentWillUnmount combined.
so in your case, you can add all the logics in the useEffect hook.

Related

NextJS useEffects Fired twice

I'm having problem with useEffect it fired twice when the page rendered my code below
useEffect(() => {
if (!jwt) {
console.log('you are not login');
} else {
console.log(cookie.GREEN_COOKIE);
}
fetchEvents();
}, []);
Something is causing your component to re-render.
Without seeing any other code or props of the component it's difficult to say what.

Infinite loop in redux-saga effect

I've been able to create an infinite loop that keeps getting data from the API.
I use useEffect conditional dispatch to run, which should only run once.
But when I look into Redux DevTools, the data retrieval from the api is in an endless loop.
Slice:
import { createSlice } from "#reduxjs/toolkit";
const initialState = { cats: [] };
const catSlice = createSlice({
name: "cat",
initialState,
reducers: {
setCat: (state, action) => {
state.cats = action.payload;
},
},
});
export const { setCat } = catSlice.actions;
export default catSlice.reducer;
Saga:
import { call, put, takeLatest } from "redux-saga/effects";
import { setCat } from "./catSlice";
function* getCatsFetch() {
const cats = yield call(() => fetch(`https://xxxapi.com`));
const formatedCats = yield cats.json();
yield put(setCat(formatedCats));
}
function* catSaga() {
yield takeLatest("cat/setCats", getCatsFetch);
}
export default catSaga;
Command in App.js
useEffect(() => {
dispatch(setCats());
}, [dispatch]);
Can you please help me stop endless requests on the api? Thanks
The issue is your getCatsFetch saga emits a setCat action. And your catSaga is waiting for any setCat to trigger another getCatsFetch saga. So even though you're only dispatching one setCat action from your component, the saga is also emitting a setCat after it successfully runs. You're looping through the middleware.
To correct the issue, you should probably change the takeLatest to be looking for some kind of getCats action instead, then emit that action in your component. (not your saga).

How to get rid of missing dependency warning of useEffect in React

import { useEffect, useState } from "react";
const useSPices = () => {
const [spices, setSpices] = useState([])
useEffect(() => {
fetch("http://localhost:5000/spices")
.then(res => res.json())
.then(data => setSpices(data))
});
return [spices, setSpices];
}
export default useSPices;
Dependency array tells useEffect when to run:
useEffect(() => {
// do smth
}, [var1, var2 ...]);
Whenever any of the variables in that array (var1 and so on) change, it causes the code inside the useEffect to execute. If you dont supply this array, the useEffect executes its code on every render.
You could do something like this:
function MyFetch(url) {
const [data, setData] = useState();
useEffect(() => {
fetch(url)
.then((res) => res.json())
.then((data) => setData(data));
}, [url]);
return [data];
}
And then you can use it like this:
export default function App() {
const data = MyFetch("https://jsonplaceholder.typicode.com/todos/1");
console.log(data[0]);
return (
<div>
{Object.keys(data[0]).map((key) => (
<div>
{key} - {data[0][key] + ""}
</div>
))}
</div>
);
}
useEffect is a tricky one to be honest with you. useEffect runs after every render (since you have no dependency array), and setState causes a re-render, so you have to be a bit careful when setting state from inside useEffect. Currently, in your code, what happens is:
useEffect runs
setState is executed, which causes a re-render
useEffect runs again because of the re-render
To avoid this, don't update things from inside the useEffect that would trigger the useEffect to re-run.
Here's the sandbox link: https://codesandbox.io/s/determined-goldstine-jx1r81?file=/src/App.js:280-567
I see that you are returning the setSpices function, what is your goal? If you want useSpices to be a function for fetching stuff asynchronously, the returning just the spices will be enough, but I can't think of a reason of why you might want to return the setSpices function as well.

Vue 3: How to implement a function that modifies all input fields in the DOM?

I'm new to Vue and want to add an onfocus function to all input fields. When I use mixin, the function is called every time a component is mounted.
createApp(App).mixin({
mounted() {
myFunction() {
document.querySelectorAll('input').doSomething()
}
}
}).mount('#app');
That makes sense and is in generally what I want, because newly added input fields should be affected, too. But then the function would iterate through the whole DOM every time a component is mounted, right? I want to avoid unnecessary iteration for fields that already have the onfocus function. So what would be best practice to do something like this?
import { createApp, h } from "vue";
import App from "./App.vue";
const app = createApp({
render: () => h(App)
});
app.mixin({
methods: {
myFunction() {
this.$el.querySelectorAll("input").forEach((el) => {
alert(el.getAttribute("name"));
});
}
},
mounted() {
this.myFunction();
}
});
app.mount("#app");

setState after an API call inside a componentDidMount

I'm trying to implement a custom select which displays a list of languages fetched from an API.
I make the api call in the componentDidMount lifecycle hook and then update the state of my component according to the data I fetched.
Everything seems to work, yet I always get this error:
Warning: setState(...): Can only update a mounted or mounting
component. This usually means you called setState() on an unmounted
component. This is a no-op. Please check the code for the
LanguageSelect component.
Here's a snippet of my code:
export default class LanguageSelect extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: false,
languages: []
};
}
// ...
componentDidMount() {
http.get('/api/parameters/languages')
.then(
// the Array.map is just to restructure the data fetched form the API
data => this.setState({ languages : data.map(l => ({ label: l.LocalName, value: l.Code, })) }),
// Error case
error => console.error('Error: Languages data could not be fetched', error)
)
}
// Render function
}
I don't understand, The only setState call I make is inside a componentDidMount() lifecycle thus is only executed when the component is mounted ?
Thanks in advance
You could use isMounted() to check if it's mounted
if (this.isMounted()) {
this.setState({...});
}
Although it's an anti pattern and you can find some proposals on best practice solutions here: https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html

Resources