1

Currently I'm working on Alarm clock app and I want to do it in way so you can add multiple Alarms. Every Alarm is stored in alarms:[] state in App.js file. If alarm is added,I want to display that alarm as a li element under the clock and I want to be able to remove it by clicking on X icon. Also ,when current time === time set for alarm ,Ring.js component renders and alarm starts ringing. When alarm is ringing there is 'turn off' button. How is it possible to delete this specific alarm which is ringing ,from state array after click on turn off button?

I've tried to send removeAlarm function and alarm(which may help in determining which alarm from array delete)as a prop to this component when condition if fulfilled.

 function checkTime(){
   if(time.alarms[0]){
     const alarms = time.alarms.map(function(alarm,i){
      if(time.currentHour === alarm.hour && time.currentMinute === alarm.minute && time.currentSecond 
      >= 0){
       return <Ring message={alarm.message} key={i} alarm={alarm} removeAlarm={removeAlarm} />
      }
    })
    return alarms;
  }
}

removeAlarm function:

  function removeAlarm(alarm){
   setTime(prevState => ({
    ...prevState,
    alarms:[...prevState.alarms.filter(el => el !== alarm)]
   }))
  }

Ring.js file

    let message = props.message;
    function removeAlarm(alarm){
      props.removeAlarm(alarm);
    }

    function turnOff(e,alarm){
      e.preventDefault();
      setShowRing(false);
      removeAlarm(alarm);
    }

    <form>
       <h3>{message}</h3>
       <button onClick={turnOff}>TURN OFF</button>
    </form>

I can't figure it out how to do that. I don't know how to use that passed function or how to determine in that onClick function that THIS is that button which has to be send to removeAlarm function ,map thru state and remove that specific one.

Also second problem which I've noticed is with React Spring Transitions. I'm using it in Ring.js,Alarm.js and want to use it also for listing active alarms in ListAlarms.js. I'm using it the exact same way as in first two components but for ListAlarms.js it's not working and I don't undestand why. My goal is to display those active alarms with transitions not just 'blink' there.

Thank you.

CodeSandBox link here

2 Answers 2

1

OK some corrections but you have to alter the transitions

First of all you need to filter your list by id, in order to remove correctly the alarm.

  function removeAlarm(alarm){
   setTime(prevState => ({
    ...prevState,
    alarms:[...prevState.alarms.filter(el => el.id !== alarm.id)]
   }))
  }

Secondly, I have removed the from property from your transition, since every new object was positioned on top of others. Also, instead of null for the key I used mapping to each item's id.

(item) => item.id

Finally I corrected the order in map function

{listAlarmTransitions.map(({ item, props, key }) => (

So it became

  const listAlarmTransitions = useTransition(props.alarms, (item) => item.id, {
    enter: { opacity: 1 },
    leave: { opacity: 0 }
  });

  return (
    <ul>
      {listAlarmTransitions.map(({ item, props, key }) => (
        <animated.div key={key} style={props}>
          <li
            key={item.id}
            id={item.id}
            onClick={() => {
              removeAlarm(item);
            }}
          >
            <FontAwesomeIcon icon={faTimesCircle} className="listIcon" />
            <h3>{item.message}</h3>
            <span>
              {item.hour}:{item.minute}
            </span>
          </li>
        </animated.div>
      ))}
    </ul>
  );

Check this sandbox https://codesandbox.io/s/broken-morning-upqwp

Sign up to request clarification or add additional context in comments.

10 Comments

thank you very much for you time and answer. It works,now I see where was the problem with animating these li elements. I wasn't mapping them and I thought it will work same as animations in other components. Can I ask you for advice in Ring.js? I still can't figure out how to delete that specific alarm which is ringing . I mean delete from state on click 'turn off'. I can't figure it out how to implement there that ID which is used id function. @Apostolos
function turnOff(e) { e.preventDefault(); setShowRing(false); removeAlarm(props.alarm); }
change this function to use the alarm passed at props and it will work. If my answer solved your problem, please dont forget to accept it. its the green tick :)
I dont know if I get it wrong,but now if i click turn off,it deletes all of the alarms :/ this is what im returning to <Ring message={alarm.message} alarm={alarm} removeAlarm={removeAlarm} /> And inside <Ring/> component I have on that turn off button onclick={turnOff} and turnOff function looks like this: function turnOff(e){e.preventDefault() ; setShowRing(false); removeAlarm(props.alarm)}
let id = time.alarms.length > 0 ? Math.max(...time.alarms.map((alarm) => alarm.id)) + 1 : 1;
|
0

You are filtering out objects/references you should filter out by id.

Your passed alarm argument is an object and your alarms filter array contains objects, find a unique property which you can filter against, by looking at your code, it should be id.

Something like this:

  function removeAlarm(alarm){
   setTime(prevState => ({
    ...prevState,
    alarms:[...prevState.alarms.filter(el => el.id !== alarm.id)]
   }))
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.