#reactjs
Вопрос:
Мне нужно знать, что я должен сделать, чтобы убедиться, что тексты всех товаров(за исключением того, который должен) не оказывают сквозного эффекта при нажатии кнопки покупки. Прямо сейчас каждый отдельный элемент в списке, как правило, имеет такой эффект, когда я нажимаю на любой из них. Кроме того, другим поведением этого компонента должно быть изменение названия кнопки на «Куплено» из покупки и наоборот при нажатии на нее. Это работает так, как должно работать, за исключением того факта, что все кнопки показывают такое поведение, а не только ту, на которую был нажат. Я использовал контекстный API для передачи данных. Скриншот, показывающий, что я имею в виду, также прилагается. Код выглядит следующим образом:
context.js
import React, {useState, useEffect, createContext} from "react";
export const FoodContext = createContext();
export const FoodProvider = (props) => {
const[food, setFood] = useState([]);
const getData = () => {
const request = {
method : 'GET',
}
fetch("http://localhost:3008/api/get", request)
.then(res => res.json())
.then(data => {
setFood(data)
})
};
useEffect(() => {
getData()
}, []);
return(
<FoodContext.Provider value={[food, setFood]}>
{props.children}
</FoodContext.Provider>
);
}
content_screen.js — Именно здесь ListItems
происходит визуализация компонента.
import React, {Component} from 'react';
import Caption from '../components/caption/caption';
import InputBar from '../components/input_bar/input_bar';
import ListItems from '../components/list_items/list_items';
import "./content_screen.css";
//This is where the ListItems component is getting rendered
export default class ContentScreen extends React.Component {
render() {
return(
<div className="content_screen">
<div className="caption">
<Caption></Caption>
<div className="search_box">
<InputBar></InputBar>
</div>
<div className="box">
<ListItems></ListItems>
</div>
</div>
</div>
);
}
}
list_items.jsx — Рассматриваемый компонент
import React,{useState, useContext} from "react";
import { FoodContext } from "../../context";
import "./list_items.css";
const ListItems = () => {
const [food, setFood] = useContext(FoodContext);
const [purchase, setPurchase] = useState(false);
const deleteItem = (id) => {
const request = {
method : 'DELETE'
};
fetch(`http://localhost:3008/api/delete/${id}`, request)
.then(res => res.json())
.then(data => console.log(data));
};
const clicked = () => {
setPurchase(!purchase);
}
return(
<div>
{!food.length ? <p>No Items Added</p> : food.map((key, value) => <div className="list_items" key={key._id}>
{purchase ? <span>{food[value].name}</span> : (food[value].name)}
<button className="x_button" onClick={() => deleteItem(food[value]._id)}>X</button>
<button className="purchase_button" onClick={clicked}>{purchase ? 'Purchased' : 'Purchase'}</button>
</div>)}
</div>
);
}
export default ListItems;
Ответ №1:
Проблема в том, что вы используете одно и то же состояние для всех из них.
Вам нужно иметь каждый товар, который имеет свое собственное состояние покупки или нет.
Создайте НОВЫЙ компонент ListItem
import React, { useState } from 'react';
export const ListItem = ({ item, deleteItem }) => {
const [purchased, setPurchased] = useState(false);
const purchase = () => {
setPurchased(!purchased)
}
return (
<div className="list_items">
{purchased ? <span>{item.name}</span> : (item.name)}
<button className="x_button" onClick={() => deleteItem(item._id)}>X</button>
<button className="purchase_button" onClick={purchase}>{purchased ? 'Purchased' : 'Purchase'}</button>
</div>
)
}
а затем в вашем ListItems
компоненте
import { ListItem } from "./ListItem";
const ListItems = () => {
const [food, setFood] = useContext(FoodContext);
const deleteItem = (id) => {
const request = {
method : 'DELETE'
};
fetch(`http://localhost:3008/api/delete/${id}`, request)
.then(res => res.json())
.then(data => console.log(data));
};
return (
<div>
{food.length
? food.map((item, key) => <ListItem item={item} key={key} deleteItem={deleteItem} />)
: <div> No food available </div>
}
</div>
)
}
Ответ №2:
для второй части: у вас есть 1 единое состояние (покупка). Все ваши товары находятся в одном и том же состоянии, то есть, если это правда, будет показано, что они куплены, а если это ложь, они покажут покупку. Вам нужно иметь для них разные состояния, или вы можете иметь одно состояние, содержащее их все ( я говорю о массиве). Вот как вы должны это сделать:
const [purchsed, setPurchased] = useState([])
//let's say this is the list of your items ( items)
for ( let i in items.length()){
setPurchased((prevState)=>[...prevState,false]
}
// Up to here we have an array containing false's. The length of the array is
// the same as your items
// give your items a name ( or another attribute that could be read from event)
<button name="item.id" className="purchase_button" onClick={clicked}>{purchase ? 'Purchased' : 'Purchase'}</button>
// This was happened when mapping
//now you can target the name attribute when you call your function
const clicked = (e) => {
let copy = [...purchased]
//make a copy of your state
copy[e.target.name] = !purchased[e.target.name]
setPurchased([...copy])
}
and your first problem is caused by the same mistake. You can follow the same pattern to fix that too. Bear in mind that this was not a quality fix, since there are some mistakes in setting up the foundation of this project.