使用 useEffect 更新状态的问题
Problem with updatig the state with useEffect
我想更新我的状态(对象列表),但我对 useEffect 或 deleteFunction 有疑问。
这是我的代码:
const [itemName, setItemName] = useState({});
const [isDeleted, setIsDeleted] = useState(false);
const createArray = () => {
const { items } = item;
const newNames = items.map(item => item);
setItemName({ ...newNames });
};
useEffect(() => {
getItems();
createArray();
}, [isDeleted]);
const onDeleteClick = id => {
deleteItem(id);
setIsDeleted(!isDeleted);
};
console.log(itemName);
return(
// Contaners and other things//
item.items.map({id, name, content}, index) =>{
// Some other code also Form and FormGroup etc. //
<Button
style={{
position: "absolute",
left: "100%",
marginLeft: "-2.2rem",
marginTop: "-0.8rem"
}}
color="danger"
size="md"
onClick={onDeleteClick.bind(this, _id)}
>×
</Button>
// rest of code
这是 deleteItem 操作:
export const deleteItem = id => (dispatch, getState) => {
axios
.delete(`/api/items/${id}`, tokenConfig(getState))
.then(res =>
dispatch({
type: DELETE_ITEM,
payload: id
})
)
.catch(err =>
dispatch(returnErrors(err.response.error, err.response.status))
);
};
和DELETE_ITEM案例缩减器:
case DELETE_ITEM:
return {
...state,
items: state.items.filter(item => item._id !== action.payload)
};
问题是在第一次点击后 "itemName" 没有改变,但在第二次点击后它起作用了。因此,例如,在开始时我有 10 个对象,单击删除后我应该有 9 个,但是 itemName 有 10 个,后来对象的数量比 itemName 对象有的多一个。
开始时:on start
第一次点击:on first click
第二次点击:on second click
最后我有 0 个对象,但 itemName 中有 1 个对象。
列表中的元素在视觉上应该会消失,但如果我删除一些元素并尝试更改其他元素的名称或内容,则会出现调整数据以更正元素的问题。
这里是 getItems 操作:
export const getItems = () => dispatch => {
dispatch(setItemsLoading());
axios
.get('/api/items')
.then(res =>
dispatch({
type: GET_ITEMS,
payload: res.data
})
)
.catch(err =>
dispatch(returnErrors(err.response.error, err.response.status))
);
};
和减速机案例:
case GET_ITEMS:
return {
...state,
items: action.payload,
loading: false
};
这是整个组件:
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 }) => {
const [itemName, setItemName] = useState({});
const [isDeleted, setIsDeleted] = useState(false);
const createArray = () => {
const { items } = item;
const newNames = items.map(item => item);
setItemName({ ...newNames });
};
useEffect(() => {
getItems();
createArray();
}, [isDeleted]);
const onChangeName = (item, index) => {
return (event) => {
const name = event.target.value;
setItemName(prevObjs => ({ ...prevObjs, [index]: { ...item[index], name } }));
console.log(itemName);
}
}
const onChangeContent = (item, index) => {
return (event) => {
const content = event.target.value;
setItemName(prevObjs => ({ ...prevObjs, index: { ...item[index], content } }));
}
}
const onDeleteClick = id => {
deleteItem(id);
setIsDeleted(!isDeleted);
};
console.log(itemName);
return (
<Container>
<div className="mb-3"></div>
<ListGroup>
<TransitionGroup >
{item.items.map(({ _id, name, content, date }, index) => (
< CSSTransition key={_id} timeout={500} classNames="fade" >
<ListGroupItem className="mb-3">
{isAuthenticated ?
<div>
<Form onSubmit={e => {
e.preventDefault();
const { name, content } = itemName[index];
const newItem = {
name,
content
}
// Add item via addItem action
updateItem(_id, newItem);
}}
>
<FormGroup>
<Button
style={{
position: "absolute",
left: "100%",
marginLeft: "-2.2rem",
marginTop: "-0.8rem"
}}
color="danger"
size="md"
onClick={onDeleteClick.bind(this, _id)}
>×
</Button>
<Label for="item">Header</Label>
<Input
type="text"
name="name"
id="item"
defaultValue={name}
// value={name}
placeholder="Add shopping item"
onChange={onChangeName(itemName, index)}
/>
<Label for="item">Content</Label>
<Input
type="textarea"
name="content"
id="item"
defaultValue={content}
// value={content}
placeholder="Add shopping item"
onChange={onChangeContent(itemName, index)}
/>
<Button
color="dark"
style={{ marginTop: '2rem' }}
block>
Change
</Button>
</FormGroup>
</Form>
</div> :
<div>
<h2>{name}</h2>
<p>{content}</p>
<p>{date.replace("T", " ").slice(0, -8)}</p>
</div>
}
</ListGroupItem>
</CSSTransition>
))}
</TransitionGroup>
</ListGroup>
</Container>
);
}
MyList.propTypes = {
getItems: PropTypes.func.isRequired,
item: PropTypes.object.isRequired,
isAuthenticated: PropTypes.bool
}
const mapStateToProps = (state) => ({
item: state.item,
isAuthenticated: state.auth.isAuthenticated
});
export default connect(
mapStateToProps,
{ getItems, deleteItem, updateItem }
)(MyList);
好的。尝试在挂载时获取项目:
useEffect(()=>{
getItems()
},[])
并在项目更改时重新创建数组(在 redux 存储中):
useEffect(() => {
const createArray = () => {
const { items } = item;
const newNames = items.map(item => item);
setItemName({ ...newNames });
};
createArray();
}, [item.items]);
编辑:
在这种情况下,使用 useMemo
可能比第二个 useEffect
和 useState
更好
const itemName = useMemo( () => {
const { items } = item;
return items.map(item => item);
}, [item.items])
我想更新我的状态(对象列表),但我对 useEffect 或 deleteFunction 有疑问。 这是我的代码:
const [itemName, setItemName] = useState({});
const [isDeleted, setIsDeleted] = useState(false);
const createArray = () => {
const { items } = item;
const newNames = items.map(item => item);
setItemName({ ...newNames });
};
useEffect(() => {
getItems();
createArray();
}, [isDeleted]);
const onDeleteClick = id => {
deleteItem(id);
setIsDeleted(!isDeleted);
};
console.log(itemName);
return(
// Contaners and other things//
item.items.map({id, name, content}, index) =>{
// Some other code also Form and FormGroup etc. //
<Button
style={{
position: "absolute",
left: "100%",
marginLeft: "-2.2rem",
marginTop: "-0.8rem"
}}
color="danger"
size="md"
onClick={onDeleteClick.bind(this, _id)}
>×
</Button>
// rest of code
这是 deleteItem 操作:
export const deleteItem = id => (dispatch, getState) => {
axios
.delete(`/api/items/${id}`, tokenConfig(getState))
.then(res =>
dispatch({
type: DELETE_ITEM,
payload: id
})
)
.catch(err =>
dispatch(returnErrors(err.response.error, err.response.status))
);
};
和DELETE_ITEM案例缩减器:
case DELETE_ITEM:
return {
...state,
items: state.items.filter(item => item._id !== action.payload)
};
问题是在第一次点击后 "itemName" 没有改变,但在第二次点击后它起作用了。因此,例如,在开始时我有 10 个对象,单击删除后我应该有 9 个,但是 itemName 有 10 个,后来对象的数量比 itemName 对象有的多一个。
开始时:on start
第一次点击:on first click
第二次点击:on second click
最后我有 0 个对象,但 itemName 中有 1 个对象。 列表中的元素在视觉上应该会消失,但如果我删除一些元素并尝试更改其他元素的名称或内容,则会出现调整数据以更正元素的问题。
这里是 getItems 操作:
export const getItems = () => dispatch => {
dispatch(setItemsLoading());
axios
.get('/api/items')
.then(res =>
dispatch({
type: GET_ITEMS,
payload: res.data
})
)
.catch(err =>
dispatch(returnErrors(err.response.error, err.response.status))
);
};
和减速机案例:
case GET_ITEMS:
return {
...state,
items: action.payload,
loading: false
};
这是整个组件:
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 }) => {
const [itemName, setItemName] = useState({});
const [isDeleted, setIsDeleted] = useState(false);
const createArray = () => {
const { items } = item;
const newNames = items.map(item => item);
setItemName({ ...newNames });
};
useEffect(() => {
getItems();
createArray();
}, [isDeleted]);
const onChangeName = (item, index) => {
return (event) => {
const name = event.target.value;
setItemName(prevObjs => ({ ...prevObjs, [index]: { ...item[index], name } }));
console.log(itemName);
}
}
const onChangeContent = (item, index) => {
return (event) => {
const content = event.target.value;
setItemName(prevObjs => ({ ...prevObjs, index: { ...item[index], content } }));
}
}
const onDeleteClick = id => {
deleteItem(id);
setIsDeleted(!isDeleted);
};
console.log(itemName);
return (
<Container>
<div className="mb-3"></div>
<ListGroup>
<TransitionGroup >
{item.items.map(({ _id, name, content, date }, index) => (
< CSSTransition key={_id} timeout={500} classNames="fade" >
<ListGroupItem className="mb-3">
{isAuthenticated ?
<div>
<Form onSubmit={e => {
e.preventDefault();
const { name, content } = itemName[index];
const newItem = {
name,
content
}
// Add item via addItem action
updateItem(_id, newItem);
}}
>
<FormGroup>
<Button
style={{
position: "absolute",
left: "100%",
marginLeft: "-2.2rem",
marginTop: "-0.8rem"
}}
color="danger"
size="md"
onClick={onDeleteClick.bind(this, _id)}
>×
</Button>
<Label for="item">Header</Label>
<Input
type="text"
name="name"
id="item"
defaultValue={name}
// value={name}
placeholder="Add shopping item"
onChange={onChangeName(itemName, index)}
/>
<Label for="item">Content</Label>
<Input
type="textarea"
name="content"
id="item"
defaultValue={content}
// value={content}
placeholder="Add shopping item"
onChange={onChangeContent(itemName, index)}
/>
<Button
color="dark"
style={{ marginTop: '2rem' }}
block>
Change
</Button>
</FormGroup>
</Form>
</div> :
<div>
<h2>{name}</h2>
<p>{content}</p>
<p>{date.replace("T", " ").slice(0, -8)}</p>
</div>
}
</ListGroupItem>
</CSSTransition>
))}
</TransitionGroup>
</ListGroup>
</Container>
);
}
MyList.propTypes = {
getItems: PropTypes.func.isRequired,
item: PropTypes.object.isRequired,
isAuthenticated: PropTypes.bool
}
const mapStateToProps = (state) => ({
item: state.item,
isAuthenticated: state.auth.isAuthenticated
});
export default connect(
mapStateToProps,
{ getItems, deleteItem, updateItem }
)(MyList);
好的。尝试在挂载时获取项目:
useEffect(()=>{
getItems()
},[])
并在项目更改时重新创建数组(在 redux 存储中):
useEffect(() => {
const createArray = () => {
const { items } = item;
const newNames = items.map(item => item);
setItemName({ ...newNames });
};
createArray();
}, [item.items]);
编辑:
在这种情况下,使用 useMemo
可能比第二个 useEffect
和 useState
更好
const itemName = useMemo( () => {
const { items } = item;
return items.map(item => item);
}, [item.items])