#reactjs #use-state
Вопрос:
Я очень новичок в реагировании и создаю свое первое в истории приложение, которое представляет собой приложение для сокращения URL-адресов. Рядом с каждым сокращенным URL-адресом есть кнопка, текст которой изначально настроен на «копировать», и как только пользователь нажимает на нее, ссылка копируется в буфер обмена, а текст кнопки изменяется на «скопировано». Все работает нормально, за исключением того, что у меня есть несколько сокращенных URL-адресов, и я нажимаю на одну из кнопок рядом с каким-либо конкретным URL-адресом, он по-прежнему копирует только этот URL-адрес в буфер обмена, но текст кнопки меняется на скопированный на всех из них. Если кто-нибудь может, пожалуйста, просветить меня, как выделить эти кнопки по отдельности, это будет очень полезно. Я пробовал использовать идентификатор, но, может быть, я делаю это неправильно?
P. S — это первый раз, когда я публикую здесь, так что заранее приношу извинения, если пропустил какие-либо важные моменты.
import {useState} from 'react'
import axios from 'axios'
import { v4 as uuidv4 } from 'uuid';
function Main() {
const [name, setName] = useState('')
const [list, setList] = useState(initialList);
const handleSubmit = (e) => {
e.preventDefault();
}
const handleAdd = async () => {
const res = await axios.get(`https://api.shrtco.de/v2/shorten?url=${name}`)
const {data: {result: {full_short_link: shortLink}}} = res
const newList = list.concat({name:shortLink, id: uuidv4()});
setList(newList);
setName('');
}
const [buttonText, setButtonText] = useState("Copy");
return (
<form onSubmit={handleSubmit}>
<input type="text"
value= {name}
onChange={(e) => setName(e.target.value)}
placeholder='Shorten a link here'
onClick = {()=> setButtonText('copy')}
/>
<button onClick = {handleAdd}>Shorten it!</button>
</form>
<ul>
{list.map((item, index) => (
<li key={item.id}>{item.name}<button
onClick = {() => { navigator.clipboard.writeText(item.name); setButtonText("Copied")}} >
{buttonText}
</button></li>))}
</ul>
export default Main``
Ответ №1:
Это связано с тем, что вы используете одну переменную состояния для всех ваших кнопок, вам нужна переменная для отслеживания состояния каждой отдельной кнопки. Вам следует преобразовать код в вашей функции карты в ее собственный компонент и объявить состояние buttonText в этом компоненте. Таким образом, каждая кнопка имеет свое собственное состояние.
Например (извините за заглавные буквы в моем коде):
MyButton.js
Const MyButton = ({item}) => {
const [buttonText, setButtonText] = useState(‘Copy’)
Return (
<li key={item.id}>{item.name}
<button
onClick = {() => {
navigator.clipboard.writeText(item.name);
setButtonText("Copied")}
}
>
{buttonText}
</button>
</li>
)
Export default MyButton
Форма:
// ……
<ul>
{list.map((item, index) => <MyButton key={item.id} item={item} />)}
</ul>
Комментарии:
1. Привет, Coot3, спасибо за ваш быстрый ответ. есть ли какой-либо способ, которым это можно сделать в одном и том же компоненте, т. е. объявить состояние для каждой кнопки. или это должен быть отдельный компонент?
2. Вы, конечно, могли бы (используя объект, то есть, например, для хранения ваших значений
{ [id]: buttonText }
), но в React вам часто следует пытаться разбивать вещи на наименьшие возможные элементы, а затем создавать из них более сложные элементы. Посмотрите здесь (если вы еще этого не сделали): reactjs.org/docs/thinking-in-react.html