Сделать "лайки" в react js
Всем доброго утра) Моя задача заключается в том,что бы выводить на экран карточки-полученные через API c помощью axios. Cделать так,чтобы они лайкались и сохраняли свое состояние.
Что я сделал Я создал функцию
const handleLike = id => {
cards(state => state.map(el => {
if (el.id === id) {
return {
...el,
liked: !el.liked,
}
}
return el;
}))
}
,которая меняет состояние и тем самым я добавляю модификатор liked к классу place-card__like-icon. Так же я передаю состояние liked классу place-card. Делаю это для того, чтобы при нажатие на кнопку я получил все "залайканые" карточки.
Что то пошло не так Почему то не работает код.
import React,{useState,useEffect} from 'react';
import axios from 'axios';
function App() {
const [isDisplay, setDisplay] = React.useState(false);
const displayAdd=()=>setDisplay(!isDisplay);
const [appState, setAppState] = useState(
{
allCards:[]
}
)
useEffect(() => {
setAppState({loading: true})
const apiUrl = 'https://test-api-921f7-default-rtdb.firebaseio.com/cards.json';
axios.get(apiUrl).then((resp) => {
const allCards = resp.data;
setAppState({
allCards
});
});
}, [setAppState]);
const likeButtonHandler = (id) => {
setAppState(
appState.map((item) =>
item.id === id ? { ...item, liked: !item.liked } : item
)
);
};
return (
<div className="app">
<div>
{appState.map(({ id, name, liked = false }) => (
<div key={id} style={{border: '1px solid black', margin: '1rem', padding: '1rem'}}>
<div>Name: {name}</div>
<div>Liked: {liked.toString()}</div>
<button onClick={() => likeButtonHandler(id)}>
{liked ? "unlike me" : "like me"}
</button>
</div>
))}
</div>
</div>
);
}
export default App;
Ответы (1 шт):
Хук useState работает не так как стейт в классе. Поэтому заводим отдельный хук-стейт на данных из axios (allCards - массив) и отдельный хук-стейт для loading-flag, для простоты и впрочем так это делается. Когда нажимается кнопка лайк - проходим по всему массиву allCards и обновляем состояние только в элементе с заданным ID, далее обновляем состояние, реакт всё перерисовывает. Во время загрузки данных можно отображать loading-spinner. У меня получилось примерно так:
// import React from "react";
// import axios from "axios";
function App() {
// const [isDisplay, setDisplay] = React.useState(false);
// const displayAdd = () => setDisplay(!isDisplay);
const [allCards, setAllCards] = React.useState([]);
const [loading, setLoading] = React.useState(false);
React.useEffect(() => {
setLoading(true);
const apiUrl =
"https://test-api-921f7-default-rtdb.firebaseio.com/cards.json";
axios.get(apiUrl).then((resp) => {
const allCards = resp.data;
setAllCards(allCards);
setLoading(false);
});
}, []);
const likeButtonHandler = (id) => {
setAllCards(
allCards.map((item) =>
item.id === id ? { ...item, liked: !item.liked } : item
)
);
};
return (
<div className="app">
<div>
{loading
? "Loading..."
: allCards.map(({ id, name, liked, link }) => (
<div
key={id}
style={{
border: "1px solid black",
margin: "1rem",
padding: "1rem",
}}
>
<div>Name: {name}</div>
<div>Liked: {liked.toString()}</div>
<img src={link} style={{ maxWidth: "100px" }} />
<button onClick={() => likeButtonHandler(id)}>
{liked ? "unlike me" : "like me"}
</button>
</div>
))}
</div>
</div>
);
}
// export default App;
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.4/axios.min.js" integrity="sha512-lTLt+W7MrmDfKam+r3D2LURu0F47a3QaW5nF0c6Hl0JDZ57ruei+ovbg7BrZ+0bjVJ5YgzsAWE+RreERbpPE1g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>