Как заставить кнопку работать для точного элемента, на который нажата кнопка, а не для всех элементов в отображаемом списке

#javascript #reactjs #arraylist #array-map

#javascript #reactjs #arraylist #массив-карта

Вопрос:

итак, у меня есть отображаемый список, который был создан из массива, и у каждого элемента в списке есть кнопка меню, которая отображает модальный для каждого элемента, теперь проблема в том, что если я нажимаю на кнопку с индексом 0 вместо отображения только для индекса 0, он отображается для всех, то же самое для всех остальныхиндексы

 import React, {useState} from 'react'
import ListModal from './listModal';


export const Todo = ({ Todos, deleteItem }) => {
    const [show, setshow] = useState(false);
    const unshow = () => {
        setshow(current => !current)
    }
    return (
        <ul>
            {
                Todos.map((item, index) => (
                    <li key={index}>
                        <button className="deleteBoard" onClick={unshow}>•••</button>
                        <span>{item}</span>
                        <ListModal value = {item} show={show} unshow = {unshow} />
                    </li>
                ))
            }
        </ul>
    );
};
 

Для ListModal установлено значение display:»none», поэтому, когда я нажимаю на кнопку, она отображает список modal наоборот

 import React, { useState } from 'react'
import firebase from 'firebase/app';
import { db } from '../Firebase/Firebase';
import { useRouteMatch } from 'react-router-dom';


const ListModal = ({ value, show, unshow }) => {
    const [text, settext] = useState(value)
    const styles = {
        display: show ? 'flex' : 'none'
    }
    const textChange = (e) => {
        settext(e.target.value)
    }
    return (
        <div className="listModal" style={styles}>
            <div className="listContent">
                <textarea value={text} rows="6" onChange={textChange}></textarea>
                <button>Save</button>
                <button onClick={unshow}>Cancel</button>
            </div>
            <div className="listOption">
                <ul>
                    <li onClick={() => {deleteItem(value);moveCard()}}>Delete</li>
                </ul>
            </div>

        </div>
    )
}
export default ListModal

 

Заранее спасибо, я не против переписать, пожалуйста, просто помогите мне. Спасибо

Ответ №1:

в родительском компоненте я настраиваю модальный и передаю значения

 Todos.map((item, index) => (
                    <li key={index}>
                        <ListModal value={item}/>
                    </li>
                ))
 

Затем в дочернем компоненте я настроил функции открытия и закрытия

 const [show, setshow] = useState(false);

const styles = {
        display: show ? 'flex' : 'none'
    }
   
    const isOpen = () => {
        setshow(show => !show);
    }

 

после этого в дочернем компоненте вы можете отобразить информацию об элементе и кнопку с помощью onclick

 //Whatever stuff you want to render from the passed in data


return (
        <span>{value}</span>
        <button onClick={() => {() => isOpen()}}>View</button>

        <div className="listModal" style={styles}>
            <div className="listContent">
                <textarea value={text} rows="6" onChange={textChange}></textarea>
                <button>Save</button>
                <button onClick={unshow}>Cancel</button>
            </div>
            <div className="listOption">
                <ul>
                    <li onClick={() => {deleteItem(value);moveCard()}}>Delete</li>
                </ul>
            </div>

        </div>
    )


 

Ответ №2:

Я бы посоветовал вам использовать следующий подход, который все еще можно улучшить:

  • вместо unshow метода создайте два метода showModal и hideModal
     const showModal = (item) => {
      setSelectedTodo(item);
      setshow(true);
    }
    const hideModal = () => {
      setSelectedTodo('');
      setshow(false);
    }
 
  • используйте другое useState для выбранного Todo
     const [selectedTodo, setSelectedTodo] = useState('')
 
  • после списка есть только один ListModal экземпляр, который получает элемент из состояния
     ...
    <ul>
    {
      Todos.map((item, index) => (
        ...
      ))
    }
    </ul>
    <ListModal value={selectedTodo} show={show} unshow = {hideModal} />
    ...
 
  • при нажатии на любую кнопку передайте текущее showModal задание методу
 
    <button className="deleteBoard" onClick={()=> showModal(item)}>•••</button>

 

Комментарии:

1. метод unshow выполняет точно то же самое, что и два рекомендованных вами метода, и не могли бы вы подробнее объяснить свое решение

2. причина, по которой я начал использовать этот метод вместо вашего заявленного метода, заключается в том, что я понял, что он замкнут и выполняет ту же функцию, но если вы считаете, что другой метод лучше, пожалуйста, объясните, почему, и я это исправлю

3. Конечно, итак, во-первых, он должен быть назван в зависимости от его функциональности, я думаю, unshow вы имеете в виду hide , но этот метод не скрывает модальный, он переключает его, показывает и скрывает, поэтому мы можем назвать его toggleModal, например, во-вторых, зачем разделять его на два метода? в моем подходе мы добавляем больше логики при отображении модального (передача и настройка выбранного Todo), это необходимо только в show, поэтому нам нужен отдельный метод для выполнения логики show, однако есть несколько лучших подходов, которые требуют большего разделения, я предложил этот для простоты

4. хорошо, теперь я понимаю, я действительно последовал вашему примеру и смог решить эту проблему, но я не изменил функцию unshow. Я опубликую свой ответ, а затем изменю его. Спасибо

Ответ №3:

Мне не нужно было ничего менять в моем компоненте listModal. Вот родительский компонент, в который я внес некоторые изменения

 import React, { useState } from 'react'
import ListModal from './listModal';

export const Todo = ({ Todos, deleteItem }) => {
    const [show, setshow] = useState(false);
    const [selected, setselected] = useState("")
    const toggle = () => {
        setshow(show => !show)
    }
    const select = (item) => {
        setselected(item)
    }
    return (
        <>
            <ul>
                {
                    Todos.map((item, index) => (
                        <li key={index}>
                            <button className="deleteBoard" onClick={() => { toggle(); select(item) }}>•••</button>
                            <span>{item}</span>
                        </li>
                    ))
                }
            </ul>
            <ListModal val={selected}  deleteItem={deleteItem} show={show} toggle={toggle} />
        </>
    );
};
 

Объяснение::
Вместо того, чтобы помещать listModal в метод map, создавая таким образом компонент listModal для каждого элемента, отображаемого в списке. Я оставил его вне метода map, поэтому у меня есть только один компонент listModal для каждого элемента в методе map. Все, что меняется, — это значения, отображаемые listModal .

Я также создал метод select, который принимает параметр (item), который является отображаемым значением, и сохраняет его в selected . выбранное — это состояние, затем я передал выбранное в listModal .

Это почти все, что я сделал, извините, если мое объяснение плохое.