Search code examples
reactjsuse-effectuse-state

useEffect is not rendering an array on DOM


I am populating an array with dummy data and once it is done, using useEffect, i'm trying to delete the the element on first index and update it on the DOM. The array is being updated on console but the changes doesn't reflect on DOM.

import './App.css';
        import { useState,useEffect } from 'react';
        import {faker} from '@faker-js/faker'
        function App() {
        
          var catsarray = []
          const [cats, changecat] = useState(()=>{
            for (let index = 0; index < 10; index++) {
              catsarray.push(faker.animal.cetacean())
            }
        
            return catsarray
          })
        
          useEffect(()=>{
           
          },[cats])
        
          const removecat = () => {
         
            cats.shift()
            changecat(cats)
          
          }
           
         return (
           <div className="App">
              <h1> List of cats </h1>  
                    <div className='wrapper'>
                    <ul>
                    <>
                    {catsarray.length > 2 ? 
                    cats.map((title, index)=>(
                       <li key={index}> {index} : {title} </li> 
                    )) : 'Array is empty' } 
                    </>
                  
                    </ul>
                    </div>
                    <button title='button' onClick={removecat}> Click me </button> 
                   
        
            </div>
          );
        }
        
        export default App;

Have a look at this image


Solution

  • The reason is like @Jacob Smit said:

    React uses referential comparisons to determine whether or not a value has changed. If you mutate (change) the state and provide it back to the setState function react sees the same value as it already has stored and thinks there is no operation to be carried out

    So you need to use a different refernece when mutating a state

    for example

    // assign a new array 
    let tempCats = [...cats]
    
    // operate this new array
    tempCats.shift()
    
    // set the new array to state
    changecat(tempCats)
    

    Or like @Jacob Smit's suggestion

    changecat(cats => cats.filter((_, i) => i !== 0))
    

    a example from your question with a little modify

    import React from "react"
    import { useState, useEffect } from 'react';
    
    function App() {
        var faker = ["steve", "john", "cat", "dog", "alex", "big"]
    
        var catsarray = []
        const [cats, changecat] = useState(() => {
            for (let index = 0; index < faker.length; index++) {
                catsarray.push(faker[index])
            }
    
            return catsarray
        })
    
        useEffect(() => {
        }, [cats])
    
        const removecat = () => {
            let tempCats = [...cats]
            tempCats.shift()
            console.log(tempCats)
            changecat(tempCats)
    
            // or @Jacob Smit's suggestion
            //changecat(cats => cats.filter((_, i) => i !== 0))
        }
    
        return (
            <div>
                <h1> List of cats </h1>
                <div>
                    <ul>
                        <>
                            {cats.length > 2 ?
                                cats.map((title, index) => (
                                    <li key={index}> {index} : {title} </li>
                                )) : 'Array is empty'}
                        </>
                    </ul>
                </div>
                <button title='button' onClick={removecat}> Click me </button>
            </div>
        );
    }
    
    export default App;
    

    a code snippet display

    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    
    <div id="root"></div>
    
    <script type="text/babel">
            function App() {
                var faker = ["steve", "john", "cat", "dog", "alex", "big"]
    
                var catsarray = []
                const [cats, changecat] = React.useState(() => {
                    for (let index = 0; index < faker.length; index++) {
                        catsarray.push(faker[index])
                    }
    
                    return catsarray
                })
    
                React.useEffect(() => {
                }, [cats])
    
                const removecat = () => {
                    let tempCats = [...cats]
                    tempCats.shift()
                    console.log(tempCats)
                    changecat(cats => cats.filter((_, i) => i !== 0))
                }
    
                return (
                    <div>
                        <h1> List of cats </h1>
                        <div>
                            <ul>
                                {cats.length > 2 ?
                                    cats.map((title, index) => (
                                        <li key={index}> {index} : {title} </li>
                                    )) : 'Array is empty'}
                            </ul>
                        </div>
                        <button title='button' onClick={removecat}> Click me </button>
                    </div>
                );
            }
    </script>
    
    <script type="text/babel">
    ReactDOM.render(
        <App></App>
        , document.getElementById("root"));
    </script>