Я хочу обновить свое состояние (список объектов), и у меня есть проблема с useEffect или deleteFunction. Вот мой код:

const [itemName, setItemName] = useState({}); const [isDeleted, setIsDeleted] = useState(false); const createArray = () ={amp}gt; { const { items } = item; const newNames = items.map(item ={amp}gt; item); setItemName({ ...newNames }); }; useEffect(() ={amp}gt; { getItems(); createArray(); }, [isDeleted]); const onDeleteClick = id ={amp}gt; { deleteItem(id); setIsDeleted(!isDeleted); }; console.log(itemName); return( // Contaners and other things// item.items.map({id, name, content}, index) ={amp}gt;{ // Some other code also Form and FormGroup etc. // {amp}lt;Button style={{ position: "absolute", left: "100%", marginLeft: "-2.2rem", marginTop: "-0.8rem" }} color="danger" size="md" onClick={onDeleteClick.bind(this, _id)} {amp}gt;{amp}amp;times; {amp}lt;/Button{amp}gt; // rest of code 

Вот действие deleteItem:

 export const deleteItem = id ={amp}gt; (dispatch, getState) ={amp}gt; { axios .delete(`/api/items/${id}`, tokenConfig(getState)) .then(res ={amp}gt; dispatch({ type: DELETE_ITEM, payload: id }) ) .catch(err ={amp}gt; dispatch(returnErrors(err.response.error, err.response.status)) ); }; 

и DELETE_ITEM регистр редуктора:

 case DELETE_ITEM: return { ...state, items: state.items.filter(item ={amp}gt; item._id !== action.payload) }; 

Проблема в том, что после первого нажатия «itemName» не изменилось, но через секунду оно работает. Так, например, на старте у меня есть 10 объектов, после нажатия «Удалить» у меня должно быть 9 из них, но у itemName их 10, позднее число объектов — это еще одно, что у объекта ItemName.

На старте: на старте

По первому клику: по первому клику

На втором клике: на втором клике

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

И вот действие getItems:

 export const getItems = () ={amp}gt; dispatch ={amp}gt; { dispatch(setItemsLoading()); axios .get('/api/items') .then(res ={amp}gt; dispatch({ type: GET_ITEMS, payload: res.data }) ) .catch(err ={amp}gt; dispatch(returnErrors(err.response.error, err.response.status)) ); }; 

и корпус редуктора:

  case GET_ITEMS: return { ...state, items: action.payload, loading: false }; 

Ok. Попробуйте получить элемент на монтировании с:

 useEffect(()={amp}gt;{ getItems() },[]) 

И воссоздать массив, когда элементы изменяются (в избыточном хранилище):

  useEffect(() ={amp}gt; { const createArray = () ={amp}gt; { const { items } = item; const newNames = items.map(item ={amp}gt; item); setItemName({ ...newNames }); }; createArray(); }, [item.items]); 

Изменить: Использование useMemo , вероятно, лучше, чем второй useEffect и useState для этого случая

 const itemName = useMemo( () ={amp}gt; { const { items } = item; return items.map(item ={amp}gt; item); }, [item.items]) 

Вот весь компонент:

 import React, { useEffect, useState } from 'react'; import { Container, ListGroup, ListGroupItem, Button, Form, FormGroup, Label, Input } from 'reactstrap'; import { CSSTransition, TransitionGroup } from 'react-transition-group'; import { connect } from 'react-redux'; import { getItems, deleteItem, updateItem } from '../actions/itemActions'; import PropTypes from 'prop-types'; const MyList = ({ getItems, deleteItem, isAuthenticated, item, updateItem }) ={amp}gt; { const [itemName, setItemName] = useState({}); const [isDeleted, setIsDeleted] = useState(false); const createArray = () ={amp}gt; { const { items } = item; const newNames = items.map(item ={amp}gt; item); setItemName({ ...newNames }); }; useEffect(() ={amp}gt; { getItems(); createArray(); }, [isDeleted]); const onChangeName = (item, index) ={amp}gt; { return (event) ={amp}gt; { const name = event.target.value; setItemName(prevObjs ={amp}gt; ({ ...prevObjs, [index]: { ...item[index], name } })); console.log(itemName); } } const onChangeContent = (item, index) ={amp}gt; { return (event) ={amp}gt; { const content = event.target.value; setItemName(prevObjs ={amp}gt; ({ ...prevObjs, index: { ...item[index], content } })); } } const onDeleteClick = id ={amp}gt; { deleteItem(id); setIsDeleted(!isDeleted); }; console.log(itemName); return ( {amp}lt;Container{amp}gt; {amp}lt;div className="mb-3"{amp}gt;{amp}lt;/div{amp}gt; {amp}lt;ListGroup{amp}gt; {amp}lt;TransitionGroup {amp}gt; {item.items.map(({ _id, name, content, date }, index) ={amp}gt; ( {amp}lt; CSSTransition key={_id} timeout={500} classNames="fade" {amp}gt; {amp}lt;ListGroupItem className="mb-3"{amp}gt; {isAuthenticated ? {amp}lt;div{amp}gt; {amp}lt;Form onSubmit={e ={amp}gt; { e.preventDefault(); const { name, content } = itemName[index]; const newItem = { name, content } // Add item via addItem action updateItem(_id, newItem); }} {amp}gt; {amp}lt;FormGroup{amp}gt; {amp}lt;Button style={{ position: "absolute", left: "100%", marginLeft: "-2.2rem", marginTop: "-0.8rem" }} color="danger" size="md" onClick={onDeleteClick.bind(this, _id)} {amp}gt;{amp}amp;times; {amp}lt;/Button{amp}gt; {amp}lt;Label for="item"{amp}gt;Header{amp}lt;/Label{amp}gt; {amp}lt;Input type="text" name="name" id="item" defaultValue={name} // value={name} placeholder="Add shopping item" onChange={onChangeName(itemName, index)} /{amp}gt; {amp}lt;Label for="item"{amp}gt;Content{amp}lt;/Label{amp}gt; {amp}lt;Input type="textarea" name="content" id="item" defaultValue={content} // value={content} placeholder="Add shopping item" onChange={onChangeContent(itemName, index)} /{amp}gt; {amp}lt;Button color="dark" style={{ marginTop: '2rem' }} block{amp}gt; Change {amp}lt;/Button{amp}gt; {amp}lt;/FormGroup{amp}gt; {amp}lt;/Form{amp}gt; {amp}lt;/div{amp}gt; : {amp}lt;div{amp}gt; {amp}lt;h2{amp}gt;{name}{amp}lt;/h2{amp}gt; {amp}lt;p{amp}gt;{content}{amp}lt;/p{amp}gt; {amp}lt;p{amp}gt;{date.replace("T", " ").slice(0, -8)}{amp}lt;/p{amp}gt; {amp}lt;/div{amp}gt; } {amp}lt;/ListGroupItem{amp}gt; {amp}lt;/CSSTransition{amp}gt; ))} {amp}lt;/TransitionGroup{amp}gt; {amp}lt;/ListGroup{amp}gt; {amp}lt;/Container{amp}gt; ); } MyList.propTypes = { getItems: PropTypes.func.isRequired, item: PropTypes.object.isRequired, isAuthenticated: PropTypes.bool } const mapStateToProps = (state) ={amp}gt; ({ item: state.item, isAuthenticated: state.auth.isAuthenticated }); export default connect( mapStateToProps, { getItems, deleteItem, updateItem } )(MyList);