react.js 中的“.map 不是函数”错误
".map is not a function" error in react.js
我使用 react-dnd 开发了一个基本的待办事项应用程序。我正在尝试从数据库中获取详细信息并将其存储在状态中。通过使用状态,我想映射从数据库中检索到的值。
我尝试使用 console.log 语句查看输出,结果是这样的。
然而,当我尝试像这样使用地图功能时:
{state.map((item, index) => (
<Draggable
key={item._id}
draggableId={item._id + ""}
index={index}
>
{console.log(item._id, "KEY")}
{(provided) => (
<li
className="list-group-item d-flex justify-content-between align-items-start align-items-center"
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
>
<div className="ms-2 me-auto">
<span className="ml-3 mr-2">
<input
type="checkbox"
className="form-check-input"
id={index}
value={index}
checked={item.selected}
onChange={(e) => {
const target = e.target.value;
const val = state[target].selected;
// console.log(val);
let tmp = Array.from(state);
tmp[target].selected = !val;
// console.log(tmp[target]);
setState(tmp);
// console.log(state);
}}
/>
</span>
<span className="font-weight-bold">{item.title}</span>
</div>
<span>
{/* <i className="bi bi-trash text-danger" /> */}
<button
className="btn btn-sm"
onClick={(e) => {
e.preventDefault();
handleDelete(item._id, index);
}}
>
<i className="bi bi-trash text-danger" />
</button>
</span>
</li>
)}
</Draggable>
它显示错误,因为“state.map”不是一个函数
不过我也尝试过使用 "state.stage.map()" 。之后它显示错误,因为 state.stage 未定义。有什么正确的方法可以使用这个 .map 函数吗?
我在下面附上了完整的代码。
function ProjectsDashboard() {
useEffect(() => {
preload();
}, []);
const [state, setState] = useState([]);
const [todo, setTodo] = useState("");
const [loading, setLoading] = useState(false);
const preload = async () => {
setLoading(true);
try {
const res = await axios.get("/stages");
setState(res.data);
console.log(state, "STATE")
console.log(res.data,"DATA")
setLoading(false);
} catch (error) {
alert("Couldn't find any Todos! ");
setLoading(false);
}
};
console.log(state, "STATE")
const lists = () => (
<div className="row">
<div className="col-sm-12 col-md-4 offset-md-2 col-lg-4 offset-lg-2 border border-danger p-4">
<h3 className="text-center mb-4">Draggable List</h3>
<DragDropContext onDragEnd={handleDragEnd}>
<Droppable droppableId="todos">
{(provided) => (
<ul
className="list-group"
{...provided.droppableProps}
ref={provided.innerRef}
>
{state.stage.map((item, index) => (
<Draggable
key={item._id}
draggableId={item._id + ""}
index={index}
>
{console.log(item._id, "KEY")}
{(provided) => (
<li
className="list-group-item d-flex justify-content-between align-items-start align-items-center"
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
>
<div className="ms-2 me-auto">
<span className="ml-3 mr-2">
<input
type="checkbox"
className="form-check-input"
id={index}
value={index}
checked={item.selected}
onChange={(e) => {
const target = e.target.value;
const val = state[target].selected;
// console.log(val);
let tmp = Array.from(state);
tmp[target].selected = !val;
// console.log(tmp[target]);
setState(tmp);
// console.log(state);
}}
/>
</span>
<span className="font-weight-bold">{item.title}</span>
</div>
<span>
{/* <i className="bi bi-trash text-danger" /> */}
<button
className="btn btn-sm"
onClick={(e) => {
e.preventDefault();
handleDelete(item._id, index);
}}
>
<i className="bi bi-trash text-danger" />
</button>
</span>
</li>
)}
</Draggable>
))}
{provided.placeholder}
</ul>
)}
</Droppable>
</DragDropContext>
</div>
<div
className="col-sm-12 col-md-4 col-lg-4 border border-info p-4"
style={{ marginLeft: "10px" }}
>
<h3 className="text-center mb-4">NON-Draggable List</h3>
<ul className="list-group">
{state.map(
(item, index) =>
item.selected && (
<li className="list-group-item" key={index}>
{item.title}
</li>
)
)}
</ul>
</div>
</div>
);
const handleDragEnd = (result) => {
// console.log(result);
if (!result.destination) return;
const items = Array.from(state);
const [recordedItem] = items.splice(result.source.index, 1);
items.splice(result.destination.index, 0, recordedItem);
setState(items);
// console.log(state);
};
const handleDelete = async (id, index) => {
try {
await axios.delete(`/api/todo/${id}`);
// preload();
const temp = Array.from(state);
temp.splice(index, 1);
setState(temp);
} catch (error) {
if (`Error! ${error.response.data.err}`) {
alert(error.response.data.err);
} else {
alert(`Error ${error.response.status}: ${error.response.statusText}`);
}
}
};
const addNewTodoForm = () => (
<div className="row">
<div className="col-md-8 offset-md-2 mb-4 form-group">
<label htmlFor="newtodo">Add a New Todo Item</label>
<input
type="text"
className="form-control"
name="newtodo"
id="newtodo"
value={todo}
placeholder="Add New Todo"
required
onChange={handleChange}
/>
<button
className="btn btn-block btn-outline-primary mt-2"
onClick={handleSubmit}
>
Submit
</button>
</div>
</div>
);
const handleChange = (e) => {
e.preventDefault();
setTodo(e.target.value);
};
const handleSubmit = async (e) => {
e.preventDefault();
if (todo === "" || todo === null) {
alert(
"To add a New Todo item, please fill out the 'Add New Todo' field."
);
return;
}
const temp = {
title: todo,
};
try {
const res = await axios.post("/api/todo", temp);
setTodo("");
const tmp = Array.from(state);
tmp.push(res.data);
setState(tmp);
// preload();
} catch (error) {
if (error.response.data && error.response.data.err) {
alert(`Error! ${error.response.data.err}`);
} else {
console.log(error);
alert(`Error ${error.response.status}: ${error.response.statusText}`);
}
}
};
return (
<>
<div className="container">
<h1 className="text-center m-4 font-weight-bold text-uppercase">
DRAG TO DO{" "}
<span className="text-lowercase font-weight-normal">V1.0.1</span>
</h1>
{/* {addNewTodoForm()}*/}
{lists() }
</div>
</>
);
};
export default ProjectsDashboard;
试试这个
{state.stage && state.stage.map(.........
这是因为在第一次渲染时,state 被初始化为一个空数组。您可以将状态初始化为:
const [state, setState] = useState({ stage: [] });
或者在调用之前写一个条件检查lists()
{state && state.stage ? lists() : null}
我使用 react-dnd 开发了一个基本的待办事项应用程序。我正在尝试从数据库中获取详细信息并将其存储在状态中。通过使用状态,我想映射从数据库中检索到的值。 我尝试使用 console.log 语句查看输出,结果是这样的。
然而,当我尝试像这样使用地图功能时:
{state.map((item, index) => (
<Draggable
key={item._id}
draggableId={item._id + ""}
index={index}
>
{console.log(item._id, "KEY")}
{(provided) => (
<li
className="list-group-item d-flex justify-content-between align-items-start align-items-center"
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
>
<div className="ms-2 me-auto">
<span className="ml-3 mr-2">
<input
type="checkbox"
className="form-check-input"
id={index}
value={index}
checked={item.selected}
onChange={(e) => {
const target = e.target.value;
const val = state[target].selected;
// console.log(val);
let tmp = Array.from(state);
tmp[target].selected = !val;
// console.log(tmp[target]);
setState(tmp);
// console.log(state);
}}
/>
</span>
<span className="font-weight-bold">{item.title}</span>
</div>
<span>
{/* <i className="bi bi-trash text-danger" /> */}
<button
className="btn btn-sm"
onClick={(e) => {
e.preventDefault();
handleDelete(item._id, index);
}}
>
<i className="bi bi-trash text-danger" />
</button>
</span>
</li>
)}
</Draggable>
它显示错误,因为“state.map”不是一个函数
不过我也尝试过使用 "state.stage.map()" 。之后它显示错误,因为 state.stage 未定义。有什么正确的方法可以使用这个 .map 函数吗? 我在下面附上了完整的代码。
function ProjectsDashboard() {
useEffect(() => {
preload();
}, []);
const [state, setState] = useState([]);
const [todo, setTodo] = useState("");
const [loading, setLoading] = useState(false);
const preload = async () => {
setLoading(true);
try {
const res = await axios.get("/stages");
setState(res.data);
console.log(state, "STATE")
console.log(res.data,"DATA")
setLoading(false);
} catch (error) {
alert("Couldn't find any Todos! ");
setLoading(false);
}
};
console.log(state, "STATE")
const lists = () => (
<div className="row">
<div className="col-sm-12 col-md-4 offset-md-2 col-lg-4 offset-lg-2 border border-danger p-4">
<h3 className="text-center mb-4">Draggable List</h3>
<DragDropContext onDragEnd={handleDragEnd}>
<Droppable droppableId="todos">
{(provided) => (
<ul
className="list-group"
{...provided.droppableProps}
ref={provided.innerRef}
>
{state.stage.map((item, index) => (
<Draggable
key={item._id}
draggableId={item._id + ""}
index={index}
>
{console.log(item._id, "KEY")}
{(provided) => (
<li
className="list-group-item d-flex justify-content-between align-items-start align-items-center"
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
>
<div className="ms-2 me-auto">
<span className="ml-3 mr-2">
<input
type="checkbox"
className="form-check-input"
id={index}
value={index}
checked={item.selected}
onChange={(e) => {
const target = e.target.value;
const val = state[target].selected;
// console.log(val);
let tmp = Array.from(state);
tmp[target].selected = !val;
// console.log(tmp[target]);
setState(tmp);
// console.log(state);
}}
/>
</span>
<span className="font-weight-bold">{item.title}</span>
</div>
<span>
{/* <i className="bi bi-trash text-danger" /> */}
<button
className="btn btn-sm"
onClick={(e) => {
e.preventDefault();
handleDelete(item._id, index);
}}
>
<i className="bi bi-trash text-danger" />
</button>
</span>
</li>
)}
</Draggable>
))}
{provided.placeholder}
</ul>
)}
</Droppable>
</DragDropContext>
</div>
<div
className="col-sm-12 col-md-4 col-lg-4 border border-info p-4"
style={{ marginLeft: "10px" }}
>
<h3 className="text-center mb-4">NON-Draggable List</h3>
<ul className="list-group">
{state.map(
(item, index) =>
item.selected && (
<li className="list-group-item" key={index}>
{item.title}
</li>
)
)}
</ul>
</div>
</div>
);
const handleDragEnd = (result) => {
// console.log(result);
if (!result.destination) return;
const items = Array.from(state);
const [recordedItem] = items.splice(result.source.index, 1);
items.splice(result.destination.index, 0, recordedItem);
setState(items);
// console.log(state);
};
const handleDelete = async (id, index) => {
try {
await axios.delete(`/api/todo/${id}`);
// preload();
const temp = Array.from(state);
temp.splice(index, 1);
setState(temp);
} catch (error) {
if (`Error! ${error.response.data.err}`) {
alert(error.response.data.err);
} else {
alert(`Error ${error.response.status}: ${error.response.statusText}`);
}
}
};
const addNewTodoForm = () => (
<div className="row">
<div className="col-md-8 offset-md-2 mb-4 form-group">
<label htmlFor="newtodo">Add a New Todo Item</label>
<input
type="text"
className="form-control"
name="newtodo"
id="newtodo"
value={todo}
placeholder="Add New Todo"
required
onChange={handleChange}
/>
<button
className="btn btn-block btn-outline-primary mt-2"
onClick={handleSubmit}
>
Submit
</button>
</div>
</div>
);
const handleChange = (e) => {
e.preventDefault();
setTodo(e.target.value);
};
const handleSubmit = async (e) => {
e.preventDefault();
if (todo === "" || todo === null) {
alert(
"To add a New Todo item, please fill out the 'Add New Todo' field."
);
return;
}
const temp = {
title: todo,
};
try {
const res = await axios.post("/api/todo", temp);
setTodo("");
const tmp = Array.from(state);
tmp.push(res.data);
setState(tmp);
// preload();
} catch (error) {
if (error.response.data && error.response.data.err) {
alert(`Error! ${error.response.data.err}`);
} else {
console.log(error);
alert(`Error ${error.response.status}: ${error.response.statusText}`);
}
}
};
return (
<>
<div className="container">
<h1 className="text-center m-4 font-weight-bold text-uppercase">
DRAG TO DO{" "}
<span className="text-lowercase font-weight-normal">V1.0.1</span>
</h1>
{/* {addNewTodoForm()}*/}
{lists() }
</div>
</>
);
};
export default ProjectsDashboard;
试试这个
{state.stage && state.stage.map(.........
这是因为在第一次渲染时,state 被初始化为一个空数组。您可以将状态初始化为:
const [state, setState] = useState({ stage: [] });
或者在调用之前写一个条件检查lists()
{state && state.stage ? lists() : null}