无法使用 Redux 和 Express.js 后端在 React 应用程序中按搜索条件获取帖子

问题描述 投票:0回答:1

我正在构建一个 React 应用程序,其中使用 Redux 进行状态管理,并使用 Express.js 后端处理 API 请求。我正在尝试实现搜索功能,以根据用户输入的搜索条件获取帖子。但是,我遇到了没有获取帖子的问题。它返回此 json 数据,而不是具有指定搜索查询的帖子

const useQuery = () => {
    return new URLSearchParams(useLocation().search)
}
export default function Home() {
    const classes = useStyles()
    const dispatch = useDispatch();
    const [search, setSearch] = useState('')
    const [tags, setTag] = useState([])
    const [currentId, setCurrentId] = useState(null)
    const liked = useSelector((state) => state.posts.isLiked)
    const del = useSelector((state) => state.posts.isDeleted)
    const query = useQuery()
    const navigate = useNavigate()
    const page = query.get('page') || 1
    const searchQuery = query.get('searchQuery')



    useEffect(() => {
        console.log('Effect triggered');
        dispatch(getPosts())
    }, [currentId, dispatch, liked, del])

    console.log(search)

    const searchingPost = () => {
        if (search.trim() || tags.length > 0) {
            dispatch(searchPost({ search, tags: tags.join(',') }))
            console.log("this is in in the search",search)

        } else {
            navigate('/')
        }
    }

    const handleKeyPress = (e) => {
        console.log("outside the if condition")
        if (e.keyCode === 'Enter') {
            searchingPost()
            console.log('inside the handlekeypress')
        }
    }

    const handleChange = (newChips) => {
        setTag(newChips)
    }

    const handleAdd = (tag) => {
        setTag([...tags, tag])

    }

    const handleDelete = (tagToDelete) => {
        setTag(tags.filter((tag) => tag !== tagToDelete))


    }


    return (
        <>
            <Grow in>
                <Container maxWidth='xl'>
                    <Grid container justify='space-between' alignItems='stretch' spacing={3} className={classes.gridContainer}>
                        <Grid item xs={12} sm={6} md={9}  >
                            <Posts currentId={currentId} setCurrentId={setCurrentId} />
                        </Grid>
                        <Grid item xs={12} sm={6} md={3}   >
                            <AppBar className={classes.appBar} position='static' color='inherit'>
                                <TextField
                                    name='search'
                                    label='Search Memories'
                                    fullWidth
                                    value={search}
                                    onChange={(e) => setSearch(e.target.value)}
                                    onKeyPress={handleKeyPress}
                                    variant='outlined'
                                />
                                <MuiChipsInput
                                    style={{ margin: '10px 0' }}
                                    value={tags}
                                    onChange={handleChange}
                                    // onAdd = {handleAdd}

                                    // onDelete = {handleDelete}
                                    label='Search Tags'
                                    variant='outlined'
                                ></MuiChipsInput>
                                <Button onClick={searchingPost} className={classes.searchButton} color='primary'>Search</Button>
                            </AppBar>
                            <Form currentId={currentId} setCurrentId={setCurrentId} />
                            <br />
                            <Paper className={classes.pagination} elevation={6}>
                                <Paginate />
                            </Paper>
                        </Grid>
                    </Grid>
                </Container>
            </Grow>

        </>
    )
}

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { fetchPostsBySearch ,fetchPosts, createPost as apiCreatePost, updatePost as apiUpdatePost, likePost, deletePost } from '../api/index.js';

const initialState = {
    isDeleted: false,
    posts: [],
    searchResults : [],
    isLiked: false
}

const postSlice = createSlice({
    name: 'posts',
    initialState,
    reducers: {
        setPosts(state, action) {
            state.posts = action.payload;
        },

        searchPost(state,action) {
            state.searchResults = action.payload;
        },
        addPost(state, action) {
            state.posts = [...state.posts, action.payload]
        },
        update(state, action) {
            const updatedPost = action.payload;
            // Find the post in the state by ID and update it

            state.posts = state.posts.map(post => (post._id === updatedPost._id ? updatedPost : post));
            // if post id equal to updated post id return updatedpost else return the previous post
            
        },
        like(state, action) {
            const postliked = action.payload;
            // Find the post in the state by ID and update it

            state.posts = state.posts.map(post => (post._id === postliked._id ? postliked : post));
            // state.posts = [...state.posts];
            state.isLiked = true;
            
            

        },
        deletepost(state, action) {
            console.log(action.payload)

            state.posts = state.posts.filter((post) => post._id !== action.payload)  
            console.log('inside the reducer',state.posts)
            // state.posts = [...state.posts];
            state.isDeleted = true

        },
        resetFlags(state) {
            state.isDeleted = false;
            state.isLiked = false;
        }




    },
});

export const { setPosts, addPost, update, like, deletepost,resetFlags,searchPost } = postSlice.actions;
export default postSlice.reducer;

export const getPosts = createAsyncThunk('posts/getPosts', async (_, { dispatch }) => {
    try {
        const { data } = await fetchPosts();
        dispatch(setPosts(data));
    } catch (error) {
        console.log(error.message);
    }
});


export const searchPosts = createAsyncThunk('posts/searchPosts', async ({searchQuery}, { dispatch }) => {
    try {
        const { data   } = await fetchPostsBySearch(searchQuery);
        dispatch(searchPost(data));
        console.log(data)
    } catch (error) {
        console.log(error.message);
    }
});


// api index.js
export const fetchPostsBySearch = (searchQuery) => API.get(`/posts/search?searchQuery=${searchQuery.search || 'none'}&tags=${searchQuery.tags}`)

查询实际上已到达后端,但请求我从后端获取它 '{搜索:'Trek',标签:''} [[原型]] '

export const getPostBySearch = async (req,res) => {
    const {searchQuery,tags} = req.query
    console.log(req.body)

    try {
        console.log(searchQuery)
        const title = new RegExp(searchQuery,'i') // i stands for ignore case
        const posts = await PostMessage.find({ $or: [{title}, {tags : { $in:  tags.split(',')}}]} )
        res.json({data : posts})

        console.log("this is for searchings posts",posts)

    } catch(error) {
        res.status(404).json({message : error.message })

    }
}

如何解决此错误我想根据标题获取帖子,但响应没有返回任何内容,并且没有显示任何错误。

javascript reactjs node.js redux mern
1个回答
0
投票

您有两个名称非常相似的操作,

searchPost
searchPosts
searchPost
是调度以更新状态的操作,以获取的“post(s)”作为操作负载,
searchPosts
是用于发起网络请求的 Thunk 操作。 UI 代码正在调度前者而不是后者,因此
state.searchResults
被设置为
{ search, tags: tags.join(',') }
中调度的
searchPost
操作中的
searchingPost
的值。

const searchingPost = () => {
  if (search.trim() || tags.length > 0) {
    dispatch(searchPost({ search, tags: tags.join(',') }));
    console.log("this is in in the search", search);
  } else {
    navigate('/');
  }
};
searchPost(state, action) {
  state.searchResults = action.payload;
},

searchingPost
应改为调度
searchPosts
Thunk 操作。

const searchingPost = () => {
  if (search.trim() || tags.length > 0) {
    dispatch(searchPosts({ search, tags: tags.join(',') }));
  } else {
    navigate('/');
  }
};

您也没有很好地利用 Redux-Toolkit。 Thunk 动作创建器实际上生成 3 个独立的动作:

.pending
.fulfilled
.rejected
。将这些添加到状态切片的
extraReducers
,而不是手动创建其他操作。

示例:

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import {
  fetchPostsBySearch,
  fetchPosts,
  createPost as apiCreatePost,
  updatePost as apiUpdatePost,
  likePost,
  deletePost
} from '../api/index.js';

const initialState = {
  isDeleted: false,
  posts: [],
  searchResults : [],
  isLiked: false
};

export const getPosts = createAsyncThunk(
  'posts/getPosts',
  async (_, { rejectWithValue }) => {
    try {
      const { data } = await fetchPosts();
      return data; // <-- return fulfilled data
    } catch (error) {
      console.log(error.message);
      return rejectWithValue(error); // <-- return rejected value
    }
  },
);

export const searchPosts = createAsyncThunk(
  'posts/searchPosts',
  async ({ searchQuery }, { rejectWithValue }) => {
    try {
      const { data } = await fetchPostsBySearch(searchQuery);
      return data; // return fulfilled value
    } catch (error) {
      console.log(error.message);
      return rejectWithValue(error); // <-- return rejected value
    }
  }
);

const postSlice = createSlice({
  name: 'posts',
  initialState,
  reducers: {
    addPost(state, action) {
      state.posts = [...state.posts, action.payload]
    },
    update(state, action) {
      const updatedPost = action.payload;

      state.posts = state.posts.map(post => (post._id === updatedPost._id ? updatedPost : post));
    },
    like(state, action) {
      const postliked = action.payload;

      state.posts = state.posts.map(post => (post._id === postliked._id ? postliked : post));
      state.isLiked = true;
    },
    deletePost(state, action) {
      state.posts = state.posts.filter((post) => post._id !== action.payload)  
      state.isDeleted = true
    },
    resetFlags(state) {
      state.isDeleted = false;
      state.isLiked = false;
    }
  },
  extraReducers: builder => {
    builder
      .addCase(getPosts.fulfilled, (state, action) => {
        state.posts = action.payload;
      })
      .addCase(getPosts.rejected, (state, action) => {
        // store error for display, etc
      })
      .addCase(searchPosts.fulfilled, (state, action) => {
        state.searchResults = action.payload;
      })
      .addCase(searchPosts.fulfilled, (state, action) => {
        // store error for display, etc
      });
  },
});

export const {
  addPost,
  update,
  like,
  deletePost,
  resetFlags
} = postSlice.actions;

export default postSlice.reducer;
© www.soinside.com 2019 - 2024. All rights reserved.