0

I have an array of messages, that are rendered into react components with array.map and key=index (in array). The array is saved to a state. I would like the messages to close, when I click on the button in the message component. I thought about passing the key variable to the Messages Component so I could use it in the closeMessage function by calling target.key somehow, but when I call the the key attribute I only get undefined. Any idea how I can do this? Thanks in advance!

function Register () {

const [errors, setErrors] = useState([{ msg: 'abc' }, { msg: 'cde' }]);

const closeMessage = ({target}) => {
        setErrors(errors => errors.splice(target.key, 1));
    }

return (
<div className="register-container">
    <h1>Register</h1>
    {errors.map((error, index) => <Messages alert="warning" msg={error.msg} key={index} close={closeMessage}/>)}
</div>
)
};
function Messages (props) {

    return(
        <div className={'message '+props.alert} key={props.key} onClick={props.close}>
            {props.msg}
            <button type="button" className="message-close">
                <span>&times;</span>
            </button>
        </div>
    )
}

3 Answers 3

1

Don't use splice in React - it'll mutate the existing array in state, and mutation is forbidden. Use the index of the clicked element to figure out how to slice the array instead:

const makeCloseMessage = i => () => {
  setErrors(
    errors.slice(0, i).concat(errors.slice(i + 1));
  );
}
close={makeCloseMessage(index)}
Sign up to request clarification or add additional context in comments.

1 Comment

This is what I was looking for! Only you have to use close={() => {makeCloseMessage(index)} in the second
0

The passing of the key attribute in your code is not correct. That's why you are getting the undefined value. Rather you can pass the index directly to the closeMessage() function.

And in case of removing the message you can use either slice() method or the filter() method. I am giving an example using the filter() method according to your code sample:

function Register () {

    const [errors, setErrors] = useState([{ msg: 'abc' }, { msg: 'cde' }]);

    const closeMessage = (key) => {
        setErrors(errors => errors.filter((item, index) => key !== index);
    }

    return (
       <div className="register-container">
         <h1>Register</h1>
         {errors.map((error, index) => <Messages alert="warning" msg={error.msg} key={index} close={() => closeMessage(index)}/>)}
       </div>
    )
 };

Comments

0

target.key is undefined when after loging target which is button tag. I think there is property to key number but I used id as key number. On button tag I added id which take props.id from Messages commponent where I gave index(I could use int index but on button tag key couldn't be props so stringified number is used). By onClick event key number can be loaded since it has index id on button tag(so with errors state, splice is possible).

function Register () {

const [errors, setErrors] = useState([{ msg: 'abc' }, { msg: 'cde' }]);

const closeMessage = ({target}) => {
        //use button tag's id for key number
        let getId = parseInt(target.id, 10);
        setErrors(errors => errors.splice(getId, 1));
    }

return (
<div className="register-container">
    <h1>Register</h1>
      {errors.map((error, index) => 
                      <Messages alert="warning" msg={error.msg} 
                      //Gave id to Messages commponent for key number
                      key={index} id={index.toString(10)} close={closeMessage}/>
                      )}

</div>
)
};

function Messages (props) {

    return(
        <div className={'message '+props.alert} key={props.key} onClick={props.close}>
            {props.msg}
            
            <button 
            //Took id by props from Messages commponent 
            id={props.id}
            type="button" 
            className="message-close">
                <span>&times;</span>

                <span>&times;</span>
            </button>
        </div>
    )
}

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.