The reason for the experienced behavior is not that useEffect isn't working. It's because of the way function components work.
If you look at your child component, if useEffect is executed and the component rerenders, defaultValues would be set to 0 again, because the code inside of the function is executed on each render cycle.
To work around that, you would need to use the useState to keep your local state consistent across renders.
This would look something like this:
function EditKat({ aa }) {
// Data stored in useState is kept across render cycles
let [defaultValues, setDefaultValues] = useState(0)
useEffect(() => {
setDefaultValues(2) // setDefaultValues will trigger a re-render
}, [aa])
console.log(defaultValues)
}
Answer from Linschlager on Stack OverflowThe reason for the experienced behavior is not that useEffect isn't working. It's because of the way function components work.
If you look at your child component, if useEffect is executed and the component rerenders, defaultValues would be set to 0 again, because the code inside of the function is executed on each render cycle.
To work around that, you would need to use the useState to keep your local state consistent across renders.
This would look something like this:
function EditKat({ aa }) {
// Data stored in useState is kept across render cycles
let [defaultValues, setDefaultValues] = useState(0)
useEffect(() => {
setDefaultValues(2) // setDefaultValues will trigger a re-render
}, [aa])
console.log(defaultValues)
}
I faced the same problem, I debugged it and i found that, i am mutating the state directly instead of cloning it and using it. So, that's why useEffect is not triggered.
I tried to download a small template that has some basic setup with vercel, supabase and next.js. Everything seems to be working but my useEffect does not get triggered so my data stays empty. I mainly just copied the Code from the template. Here is the addition, i only get the Console log the the Component is rendered, and the supabase Client gets all the correct data.
'use client'
import { createClient } from '@/utils/supabase/client'
import { useEffect, useState } from 'react'
export default function Page() {
const [beachscore, setBeachscore] = useState<any[] | null>(null)
const [error, setError] = useState<any>(null)
const supabase = createClient()
useEffect(() => {
console.log('useEffect triggered') // Log when useEffect is triggered
const getData = async () => {
try {
console.log('Fetching data from BeachScore table...')
const { data, error } = await supabase.from('BeachScore').select()
if (error) {
throw error
}
console.log('Data fetched:', data)
setBeachscore(data)
} catch (error) {
console.error('Error fetching data:', error)
setError(error)
}
}
getData()
}, []) // No dependencies specified
console.log('Component rendered') // Log when component is rendered
if (error) {
return <div>Error fetching data: {error.message}</div>
}
return <pre>{JSON.stringify(beachscore, null, 2)}</pre>
}
'use client'
import { createClient } from '@/utils/supabase/client'
import { useEffect, useState } from 'react'
export default function Page() {
const [beachscore, setBeachscore] = useState<any[] | null>(null)
const [error, setError] = useState<any>(null)
const supabase = createClient()
useEffect(() => {
console.log('useEffect triggered') // Log when useEffect is triggered
const getData = async () => {
try {
console.log('Fetching data from BeachScore table...')
const { data, error } = await supabase.from('BeachScore').select()
if (error) {
throw error
}
console.log('Data fetched:', data)
setBeachscore(data)
} catch (error) {
console.error('Error fetching data:', error)
setError(error)
}
}
getData()
}, []) // No dependencies specified
console.log('Component rendered') // Log when component is rendered
if (error) {
return <div>Error fetching data: {error.message}</div>
}
return <pre>{JSON.stringify(beachscore, null, 2)}</pre>
}I am trying to setState inside useEffect but the useEffect is not getting triggered at all
import React, { useEffect, useState } from 'react'
import items from './data'
const RoomContext = React.createContext();
const RoomProvider = ({children}) => {
const [state, setState] = useState({
rooms: [],
sortedRooms: [],
featuredRooms: [],
loading: true,
})
const formatData =(items) => {
let tempItems = items.map((item)=> {
let id = item.sys.id;
let images = item.fields.images.map(image => image.fields.file.url);
let room= {...item.fields, images,id};
return room;
});
return tempItems;
}
useEffect(()=> {
console.log(items)
let rooms= formatData(items);
console.log(rooms)
let featuredRooms = rooms.filter(room => room.featured === true)
console.log("aaaaaaa",featuredRooms)
setState({
rooms,
sortedRooms: rooms,
featuredRooms,
loading: false
})
console.log("render")
},[state])
console.log("dying")
return (
<RoomContext.Provider value={{state,setState}}>
{children}
</RoomContext.Provider>
)
}
const RoomConsumer = RoomContext.Consumer;
export { RoomContext, RoomProvider, RoomConsumer };Here's my App.js component
App.js
function App() {
return (
<GithubProvider>
<AlertProvider>
<Router>
<div className="flex flex-col justify-between h-screen">
<Navbar />
<main className='container mx-auto px-3 pb-12'>
<Alert />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/user/:login" element={<User />} /> {/* ISSUE */}
<Route path="*" element={<NotFound />} />
</Routes>
</main>
<Footer />
</div>
</Router>
</AlertProvider>
</GithubProvider>
);
}The route change to the user component happens in Home Component, I search for a github profile,
a lift of profiles are displayed, I click on the visit profile button on the profile card, which Links me to User component
UserItem.js:
import { Link } from 'react-router-dom'
import PropTypes from 'prop-types'
const UserItem = ({user: {login, avatar_url}}) => {
return (
<div className='card shadow-md compact side bg-base-600'>
<div className='flex-row items-center space-x-4 card-body'>
<div>
<div className='avatar'>
<div className='rounded-full shadow w-14 h-14'>
<img src={avatar_url} alt='Profile' />
</div>
</div>
</div>
<div>
<h2 className='card-title'>{login}</h2>
<Link
className='text-base-content text-opacity-60'
to={`/user/${login}`}
>
Visit Profile {/* TRIGGERING HERE!!!!!!!!!!! */}
</Link>
</div>
</div>
</div>
)
}
UserItem.propTypes = {
user: PropTypes.object.isRequired,
}
export default UserItem;My user Component where the function getUser needs to be triggered->
The function getUsers works fine as when i used it outside an useEffect, it did give me the right response from the fetch call inside.
User.js
import React, { useEffect, useContext } from 'react'
import {FaCodepen, FaStore, FaUserFriends, FaUsers} from 'react-icons/fa'
import { Link } from 'react-router-dom'
import GithubContext from '../context/github/GithubContext'
import { useParams } from 'react-router-dom'
import Spinner from '../components/layout/Spinner'
import RepoList from '../components/repos/RepoList'
export const User = () => {
const params = useParams()
const { getUser, user, loading, getUserRepos, repos } =
useContext(GithubContext)
console.log("params", params, "login", params.login) // WORKS FINE
useEffect ( () => {
console.log("use-effect", getUser, "", params.login)
getUser(params.login)
getUserRepos(params.login)
},[params.login]) // DOESNT TRIGGER WITH [] or [params.login]
console.log( "user-check",user) // user object empty
const {
name,
type,
avatar_url,
location,
bio,
blog,
twitter_username,
login,
html_url,
followers,
following,
public_repos,
public_gists,
hireable,
} = user
console.log("YES THIS PAGE") // Here I was checking whether page is being mounted and YES it is being mounted
const websiteUrl = blog?.startsWith('http') ? blog : 'https://' + blog
if(loading){
return <Spinner />
}
return (<> TYPICAL INFORMATION DISPLAY UI </>)
}The array you pass as second argument to useEffect only checks if the elements in the array are === to the elements in it in the previous render. const newArr = arr; will lead to newArr === arr since it doesn't create a new array, which is not what you want.
Create a new array with all the elements in arr and it will work as expected.
const App = props => {
const { arr, setArr } = useContext(GlobalContext)
const handleChange = () => {
const newArr = [...arr]
[10, 20, 30, 40].forEach(v => {
newArr.push(v)
})
setArr(newArr)
}
return <>{/* ... */}</>
}
When you want to update array using useState hook. Make sure to spread the array into new array and update the new array so that your useEffect listening for this state will be called.
UseEffect will not call in the below code snippet as you are directly updating array.
const [skills, selectedSkills] = useState([])
const onSelect = (selectedList) => {
selectedSkills(selectedList)
}
useEffect(() => {
MyLogger('useEffect called')
}, [skills])
UseEffect will call in the below code snippet as we are keeping new reference to the array.
const [skills, selectedSkills] = useState([])
const onSelect = (selectedList) => {
const tempSelectedList = [...selectedList]
selectedSkills(tempSelectedList)
}
useEffect(() => {
MyLogger('useEffect called')
}, [skills])
Hello,
I have a functional object which has three variables managed by the useState hook. These are categories, activeCategories and shownGames. For now I need something simple - run a function when categories update. I am using useEffect hook but it doesn't seem to work.
This is the code for the needed parts - https://pastie.io/uyakqz.js
I use JSON.stringify to check for the category updates (found that solution on StackOverflow). The issue is that the function specified in the useEffect hook doesn't run (it only runs when I load my page). Any help is appreciated!