javascript - 当状态改变时,useSelector 不会重新渲染组件
问题描述
我正在开发一个新闻聚合器,我有一个Newsfeed
组件可以映射相关帖子并Post
为每个帖子创建一个组件。有一个Sidebar
组件向用户显示他们订阅的订阅源,并允许他们订阅新订阅源或取消订阅现有订阅源。我想要发生的是:
- 当用户添加新提要时,会重新
Newsfeed
呈现并显示来自新提要的帖子。 - 当用户删除一个提要时,
Newsfeed
重新呈现并且不再显示来自该特定提要的帖子。
就检索正确的帖子而言 - 我的后端会处理这个问题,并且工作正常。后端根据用户订阅的提要返回帖子。问题是,当用户添加或删除提要时,Newsfeed
组件不会重新呈现,并且需要重新加载页面才能显示更新的提要。然而与此同时,Redux 存储更新了,我可以通过 Redux 开发工具看到每次状态的变化。
在Newsfeed
中,我使用useSelector
钩子来获取一些不同的状态,但是当状态改变时组件不会重新渲染。我的印象是,当状态改变时,任何使用useSelector
钩子的组件都会自动重新渲染,但如果这不是钩子的工作方式,请纠正我。
Newsfeed.tsx
:
import React, { useState, useRef, useCallback } from "react";
import usePostFetch from "../hooks/usePostFetch";
import { Post } from "./Post";
import { Tag } from "./Tag";
import { Upvote } from "./Upvote";
import { getDate } from "../services/getDate";
import { useSelector } from "react-redux";
import { InitialState } from "../store/reducers/rootReducer";
export const Newsfeed = (props: any) => {
const userState = useSelector((state: InitialState) => {
return state.auth;
});
const { user } = userState;
const publisherState = useSelector((state: InitialState) => {
return state.publishers.publishers;
});
const [pageNumber, setPageNumber] = useState(1);
const { loading, error, posts, hasMore } = usePostFetch(pageNumber);
const observer: any = useRef();
const lastPostElementRef = useCallback(
(node) => {
if (loading) return;
if (observer && observer.current) observer.current.disconnect();
observer.current = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting && hasMore) {
console.log("Visible ");
setPageNumber((prevPageNumber) => prevPageNumber + 1);
}
});
if (node) observer.current.observe(node);
console.log(node);
},
[loading, hasMore]
);
return (
<div className="container mx-auto bg-gray-900" id="newsfeed">
<div className="object-center grid grid-cols-1 gap-8 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 mx-auto pb-6 pt-6">
{posts.map((post, index) => {
return (
<Post
key={post.id}
title={post.title}
url={post.url}
image={post.image}
category={post.category}
postId={post._id}
created={post.created}
publisher={post.publisher}
upvotes={post.upvotes}
/>
);
})}
</div>
<div>{loading && "Loading..."}</div>
<div>{error && "Error"}</div>
</div>
);
};
publisherActions.ts
:(相关部分)
export const removeFeed = (allFeeds: any, feedName: any, userId: any) => async (
dispatch: Dispatch<PublisherDispatchTypes>
) => {
try {
axios({
method: "PUT",
url: "users/removepublisher",
params: { publisher: feedName, userId },
})
.then((res) => {
let newAllFeeds = allFeeds.filter((feed: any) => {
return feed.name.localeCompare(feedName) !== 0;
});
allFeeds = newAllFeeds;
console.log(`Feed was removed, ${res}`);
dispatch({
type: REMOVE_FEED_SUCCESS,
payload: allFeeds,
});
})
.catch((err) => {
console.log(`Error removing feed, ${err}`);
dispatch({
type: REMOVE_FEED_FAILURE,
});
});
} catch {
dispatch({ type: REMOVE_FEED_FAILURE });
console.log("Caught error while removing feed");
}
};
export const addFeed = (allFeeds: any, feed: any, userId: any) => async (
dispatch: Dispatch<PublisherDispatchTypes>
) => {
console.log("IN THE ADD_FEED FUNCTION");
try {
axios({
method: "PUT",
url: "users/addpublisher",
params: { publisher: feed, userId },
})
.then((res) => {
console.log(`Feed was added, ${res}`);
dispatch({
type: ADD_FEED_SUCCESS,
payload: {
name: feed.name,
url: feed.url,
image: feed.image,
},
});
})
.catch((err) => {
console.log(`Error adding feed, ${err}`);
dispatch({
type: ADD_FEED_FAILURE,
});
});
} catch {
dispatch({ type: ADD_FEED_FAILURE });
console.log("Caught error while adding feed");
}
publisherReducer.ts
:(相关部分)
import { Reducer } from "react";
import {
PublisherDispatchTypes,
REMOVE_FEED_SUCCESS,
REMOVE_FEED_FAILURE,
ADD_FEED_SUCCESS,
ADD_FEED_FAILURE,
} from "../actions/publisherActionsTypes";
import { Publisher } from "../../../../shared/Publisher";
interface PublisherResponse {
publishers: Publisher[];
}
export interface PublisherState {
publishers: Publisher[] | undefined;
loadedUsersFeeds: boolean;
feedCount: number;
}
const defaultState: PublisherState = {
publishers: undefined,
loadedUsersFeeds: false,
feedCount: 0,
};
const publisherReducer = (
state: PublisherState = defaultState,
action: PublisherDispatchTypes
) => {
switch (action.type) {
case REMOVE_FEED_SUCCESS:
return {
...state,
publishers: action.payload,
};
case REMOVE_FEED_FAILURE:
return state;
case ADD_FEED_SUCCESS:
let pubs = state.publishers || [];
return {
...state,
publishers: [...pubs, action.payload],
};
case ADD_FEED_FAILURE:
return state;
default:
return state;
}
};
export default publisherReducer;
解决方案
推荐阅读
- sql - 为什么雪花在转换为扁平列表时会改变 JSON 值的顺序?
- nativescript - 尝试使用 crashlytics 分发本机脚本构建
- javascript - 如何识别地图上的设置标记?
- r - 有没有办法在 R 中调用 PostgreSQL tablefunc 模块?
- c# - C# 用正则表达式替换多对(用于 CLR SQL Server)
- html - CSS flex with space-between 对齐项目偏离中心
- mysql - 错误 1136 (21S01):列计数与值计数不匹配,但给出相同数据类型的相同数量的值
- laravel - 有没有办法让一个 10 月的实例与一个 Laravel 应用程序在同一个项目中一起工作?
- google-app-engine - 如何增加 Cloud Scheduler 请求超时期限?
- javascript - 在没有流的情况下使用 Node.js 获取 JSON 对象