Home > Mobile >  Why am I not getting a re-render, when using map function to list components?
Why am I not getting a re-render, when using map function to list components?

Time:02-20

I wanted to make a notification component but ran into some issues.

First of all, I didn't notice the bug, because I set the array, and didn't push to it. I can confirm that it's pushing it to the array, but for some reason, it's not updating in React.

I already set keys as a timestamp, but still not working.

import './App.css';
import { v4 as uuid } from 'uuid';
import { React, useState } from 'react';
import { animated, Spring} from 'react-spring';

function App() {
    var notifications = [
        {
            "identifier": new Date().getTime(),
            "title": "lath",
            "content": "react is good",
            "type": true,
        }
    ]
    // window.addEventListener("message", (event) => {
    //     let data = event.data ?? undefined
    //     switch (data.type) {
    //         case "sendNotify":
    //             console.log(data)
    //         break
    //     }
    // });
    // addToNotify()
    function addToNotify() {
        notifications.push({
            // "identifier": uuid().slice(0,8),
            "identifier": new Date().getTime(),
            "title": "lath",
            "content": "this is a test",
            "type": true,
        })
        console.log(notifications)
    }
    
    return [
        <button key="clickBtn" onClick={() => addToNotify()}></button>,
        <div key="notify-wrap" className="notify-wrapper">
            {notifications.map(notif => (
                // console.log(notif),
                <Notification key={notif.identifier   "-key"} title={notif.title} content={notif.content} type={notif.type} identifier={notif.identifier}/>
            ))}
        </div>,
    ]
}

function Notification(props) {

    // var key = uuid().slice(0,8)
    // console.log(props)

    return (
        <Spring config={{duration: 500}} from={{ opacity: 0 }} to={{opacity : 1}}>
            {styles => 
            <animated.div key={props.identifier} className="notify-container" style={styles}>
                <div key={props.identifier   "-header-container"} className="notify-header-container">
                    <h1 key={props.identifier   "-header"} className="notify-header">{props.title}</h1>
                    <img key={props.identifier   "-header-img"} className="notify-icon" src={`img/${props.type ? "check" : "cross"}.png`}></img>
                </div>
                <p key={props.identifier   "-content"} className="notify-text">{props.content}</p>
            </animated.div>
            }
        </Spring>
    );
}

export default App;

CodePudding user response:

You should use a useState hook to handle the notifications state, so that every time a new notification is added to the array, the useState triggers a re-render with the new state.

Change your code to:

import { v4 as uuid } from "uuid";
import { React, useState } from "react";
import { animated, Spring } from "react-spring";

const sampleNotification = {
  // "identifier": uuid().slice(0,8),
  identifier: new Date().getTime(),
  title: "lath",
  content: "this is a test",
  type: true
};

function App() {
  // use useState() and initialize it with your notifications array
  var [notifications, setNotifications] = useState([
    {
      identifier: new Date().getTime(),
      title: "lath",
      content: "react is good",
      type: true
    }
  ]);

  function addToNotify(notification) {
    // change the state by appending the new notification to the previous state
    setNotifications((prevNotifications) =>
      prevNotifications.concat(notification)
    );
    console.log(notifications);
  }

  return [
    <button
      key="clickBtn"
      onClick={() => addToNotify(sampleNotification)}
    ></button>,
    <div key="notify-wrap" className="notify-wrapper">
      {notifications.map((notif) => (
        // console.log(notif),
        <Notification
          key={notif.identifier   "-key"}
          title={notif.title}
          content={notif.content}
          type={notif.type}
          identifier={notif.identifier}
        />
      ))}
    </div>
  ];
}

[...]
 
export default App;

CodePudding user response:

You should rather create a state to store your notifications in. Each time the state is updated, it'll trigger an re-render.

const [notifications , setNotifications] = useState([
        {
            "identifier": new Date().getTime(),
            "title": "lath",
            "content": "react is good",
            "type": true,
        }
    ])
    
    const addToNotify = () => {
        const notisObj = {
            "identifier": new Date().getTime(),
            "title": "lath",
            "content": "this is a test",
            "type": true,
        }
        
        setNotifications((curVal) => [...curVal, notisObj]);
    }

CodePudding user response:

Thanks for your answers! I'm so thankful, was banging my head before! Preview

  • Related