无法读取未定义的属性(读取"查找")



我正在用redux进行CRUD。该应用程序有一个带有用户名的表单,然后有一个创建、查看、编辑和删除帖子的屏幕,我正在进行编辑。然而,当我使用array.find()遍历数组并查找每个帖子时,我会得到以下错误:

无法读取未定义(读取"find"(的属性

我将留下下面的代码。

编辑屏幕:

import React, {useState} from 'react';
import '../_assets/modal.css';
import { useDispatch, useSelector } from 'react-redux';
import { useLocation, useNavigate } from 'react-router-dom'
import {editPost} from '../redux/postsslice';
function EditModal({ closeModal}) {
const { pathname } = useLocation();
const postId = pathname.replace("/edit-post/", "")
const post  = useSelector((state) => state.posts.find((post) => post.id === postId))
const dispatch = useDispatch()
const navigation = useNavigate();
const [title, setTitle] = useState(post.title)
const [content, setContent] = useState(post.content)

const onTitleChanged = e => setTitle(e.target.value)
const onContentChanged = e => setContent(e.target.value)
const onSavePostClicked = (e) => {
if (title && content) {
dispatch(editPost({id: postId, title, content}))
}

}

return (
<div className="modalBackground">
<div className="modalContainer">
<div className="title"><h1>Edit item</h1></div>
<h2>Title</h2>
<form>
<input
type="text"
placeholder="Hello World"
name="name"
value={title}
onChange={onTitleChanged}
></input>
<h2>Content</h2>
<textarea
placeholder="Content"
name="content"
value={content}
onChange={onContentChanged}
></textarea>

<button onClick={onSavePostClicked}>SAVE</button></form>

</div>
</div>
)
}
export default EditModal

主屏幕:

import React, { useState, useEffect } from "react";
import "../_assets/App.css";
import "../_assets/mainscreen.css";
import { MdDeleteForever } from "react-icons/md";
import { FiEdit } from "react-icons/fi";
import { useSelector } from 'react-redux';
import { useDispatch } from 'react-redux';
import { Navigate } from 'react-router-dom';
import { addPost } from '../redux/postsslice'
import {nanoid} from 'nanoid'
import Modal from "../components/modal.jsx";
import EditModal from '../components/editmodal.jsx';
function MainScreen() {
const dispatch = useDispatch();
const user = useSelector((state) => state.user)
const posts = useSelector((state) => state.loadPosts)
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const [buttonGreyOut, setButtonGreyOut] = useState("#cccccc");
useEffect(() => {
if (title && content !== "") {
setButtonGreyOut("black");
} else {
setButtonGreyOut("#cccccc");
}
},[title, content]);
const handleSubmitSendPost = (e) => {
e.preventDefault();
dispatch(
addPost({
id: nanoid(),
title,
content
})
)
setTitle('')
setContent('')
};
const handleChangeTitle = (text) => {
setTitle(text);
};
const handleChangeContent = (text) => {
setContent(text);
};
const [openEditModal, setOpenEditModal] = useState();
const [openModal, setOpenModal] = useState();
if (user === '') {
return <Navigate to="/" />
} else {
return (
<div className="containerMainScreen">
{openModal && <Modal closeModal={setOpenModal} />}
{openEditModal && <EditModal closeModal={setOpenEditModal} />}
<div className="bar">
<h1>Codeleap</h1>
</div>
<div className="boxPost">
<h2 style={{ fontWeight: 700 }}>What's on your mind?</h2>
<h2>Title</h2>
<form onSubmit={handleSubmitSendPost}>
<input
type="text"
placeholder="Hello World"
name="name"
value={title}
onChange={(e) => handleChangeTitle(e.target.value)}
></input>
<h2>Content</h2>
<textarea
placeholder="Content"
name="content"
value={content}
onChange={(e) => handleChangeContent(e.target.value)}
></textarea>
<button
className="createButton"
type="submit"
style={{ backgroundColor: buttonGreyOut }}
disabled={!title || !content}
>
CREATE
</button>
</form>
</div>

{posts.map((post) => (
<div className="boxPost" key={post.id}>
<div className="bar">
<h1>{post.title}</h1>
<MdDeleteForever
className="icon"
onClick={() => {
setOpenModal(true);
}}
/>
<FiEdit
onClick={() => {
setOpenEditModal(true);
}}
style={{ color: "white", fontSize: "45px", paddingLeft: "23px" }}
/>
</div>
<div id="postowner">
<h3>@{user}</h3>
<br></br>
<textarea style={{ border: "none" }}>{post.content}</textarea>
</div>
</div>
))}
</div>
);
}


}export default MainScreen;

postSlice:

import { createSlice } from "@reduxjs/toolkit";
const postsSlice = createSlice({
name: "posts",
initialState: [],
reducers: {
addPost (state, action) {
state.push(action.payload); // modifies the draft state.
},
editPost(state, action) {
const { id, title, content } = action.payload;
const existingPost = state.find((post) => post.id === id);
if (existingPost) {
existingPost.title = title
existingPost.content = content
}
}
}
});
export const { addPost, editPost } = postsSlice.actions
export default postsSlice

editModal.js(编辑页面(

import React, {useState} from 'react';
import '../_assets/modal.css';
import { useDispatch, useSelector } from 'react-redux';
import { useLocation, useNavigate } from 'react-router-dom'
import {editPost} from '../redux/postsslice';
export function EditModal({ closeModal}) {
const { pathname } = useLocation();
const postId = parseInt(pathname.replace("edit-post/", ""))
const post = useSelector((state) => state.loadPosts.find((post) => post.id === postId))
const dispatch = useDispatch()
const navigation = useNavigate();

const [title, setTitle] = useState(post.title)
const [content, setContent] = useState(post.content)

const onTitleChanged = e => setTitle(e.target.value)
const onContentChanged = e => setContent(e.target.value)
const onSavePostClicked = (e) => {
if (title && content) {
dispatch(editPost({id: postId, title, content}))
}

}

return (
<div className="modalBackground">
<div className="modalContainer">
<div className="title"><h1>Edit item</h1></div>
<h2>Title</h2>
<form>
<input
type="text"
placeholder="Hello World"
name="name"
value={title}
onChange={onTitleChanged}
></input>
<h2>Content</h2>
<textarea
placeholder="Content"
name="content"
value={content}
onChange={onContentChanged}
></textarea>

<button onClick={onSavePostClicked}>SAVE</button></form>

</div>
</div>
)
}
export default EditModal

store.js:

import { configureStore } from '@reduxjs/toolkit';
import userSlice from './userslice';
import postsSlice from './postsslice'
const store = configureStore({
reducer: {
user: userSlice.reducer,
loadPosts: postsSlice.reducer
},
})
export default store

注册页面:

import React, {useState, useEffect} from "react";
import "../_assets/signup.css";
import "../_assets/App.css";
import { useDispatch } from 'react-redux';
import userSlice from '../redux/userslice';
import { useNavigate } from "react-router-dom";
function Signup() {
const navigate = useNavigate();
const dispatch = useDispatch();
const [name, setName] = useState('')
const [buttonGrey, setButtonGrey] = useState('#cccccc')

useEffect(() => {

if (name!== '') {

setButtonGrey("black")
}  
else {
setButtonGrey('#cccccc')

}
}, [name])

const handleSubmitForm= (e) => {
e.preventDefault()
dispatch(userSlice.actions.saveUser(name))
navigate("/main")
}

const handleChangeName = (text) => {
setName(text)
}
return (
<div className="container">
<div className="LoginBox">
<form onSubmit={handleSubmitForm}>
<h2>Welcome to codeleap network</h2>
<text>Please enter your username</text>
<input type="text" name="name" value={name} onChange = {e => handleChangeName(e.target.value)}  placeholder="Jane Doe"  />
<div className="button">
<button type="submit" style={{backgroundColor: buttonGrey}}  disabled={!name} >
ENTER
</button>
</div>
</form>
</div>
</div>
);
}
export default Signup;

具有状态形状:

const store = configureStore({
reducer: {
user: userSlice.reducer,
loadPosts: postsSlice.reducer
},
});

那么posts状态的路径是state.loadPosts,所以EditModal中的选择器应该是:

const post  = useSelector((state) => state.loadPosts.find(
(post) => post.id === postId),
);

错误TypeError: Cannot read properties of undefined (reading 'title')与这行代码密切相关。如果state.loadPosts是空数组id没有匹配的posts,则.find返回undefined。

const [title, setTitle] = useState(post.title); // <-- throws error on undefined post
const [content, setContent] = useState(post.content); // <-- throws error on undefined post

一个快速的解决方案可以是使用可选的链式操作员

const [title, setTitle] = useState(post?.title);
const [content, setContent] = useState(post?.content);

但这仅设置初始状态。如果没有匹配的帖子可以编辑,那么呈现编辑UI就没有意义了。在这一点上,您应该呈现一些回退UI或导航回,等等…

相关内容

  • 没有找到相关文章