- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 Reactjs 和 Redux 构建一个聊天应用程序。我有 2 个名为 ChatHeads 和 ChatBox 的组件,它们同时并排安装。
在 ChatHeads 组件中,可以选择用户(您想要与之聊天的用户),并且此选择作为 chatInfo
存储在 redux 存储中。
ChatHeads 组件:
function ChatHeads(props) {
const {
dispatch,
userInfo,
userId
} = props;
const [chatHeads, setChatHeads] = useState([]);
const handleChatHeadSelect = (chatHead, newChat = false) => {
dispatch(
chatActions.selectChat({
isNewChat: newChat,
chatId: chatHead.chat._id,
chatUser: chatHead.user
})
);
};
const loadChatHeads = async () => {
const response = await services.getRecentChats(userId, userInfo);
setChatHeads(response.chats);
};
useEffect(() => loadChatHeads(), [userInfo]);
return (
// LOOPING THOUGH ChatHeads AND RENDERING EACH ITEM
// ON SELECT OF AN ITEM, handleChatHeadSelect WILL BE CALLED
);
}
export default connect(
(state) => {
return {
userInfo: state.userInfo,
userId: (state.userInfo && state.userInfo.user && state.userInfo.user._id) || null,
selectedChat: (state.chatInfo && state.chatInfo.chat && state.chatInfo.chat._id) || null
};
},
null,
)(ChatHeads);
聊天操作和缩减器:
const initialState = {
isNewChat: false,
chatId: '',
chatUser: {},
};
const chatReducer = (state = initialState, action) => {
let newState;
switch (action.type) {
case actions.CHAT_SELECT:
newState = { ...action.payload };
break;
default:
newState = state;
break;
}
return newState;
};
export const selectChat = (payload) => ({
type: actions.CHAT_SELECT,
payload,
});
在 ChatBox 组件中,我建立了到服务器的套接字连接,并基于全局存储和 ws 事件中的 chatInfo
对象,执行了一些操作。
聊天框组件:
let socket;
function ChatBox(props) {
const { chatInfo } = props;
const onWSMessageEvent = (event) => {
console.log('onWSMessageEvent => chatInfo', chatInfo);
// handling event
};
useEffect(() => {
socket = services.establishSocketConnection(userId);
socket.addEventListener('message', onWSMessageEvent);
return () => {
socket.close();
};
}, []);
return (
// IF selectedChatId
// THEN RENDER CHAT
// ELSE
// BLANK SCREEN
);
}
export default connect((state) => {
return {
chatInfo: state.chatInfo
};
}, null)(ChatBox);
步骤:
chatInfo
对象已正确填充。chatInfo: {
isNewChat: false,
chatId: '603326f141ee33ee7cac02f4',
chatUser: {
_id: '602a9e589abf272613f36925',
email: '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8df8fee8ffbfcde0ece4e1a3eee2e0" rel="noreferrer noopener nofollow">[email protected]</a>',
firstName: 'user',
lastName: '2',
createdOn: '2021-02-15T16:16:24.100Z',
updatedOn: '2021-02-15T16:16:24.100Z'
}
}
chatInfo
属性应该具有最新值。但是,我总是得到初始状态而不是更新后的状态。chatInfo: {
isNewChat: false,
chatId: '',
chatUser: {}
}
我在这里缺少什么?请建议...
最佳答案
出现此行为的原因是当您声明回调时
const { chatInfo } = props;
const onWSMessageEvent = (event) => {
console.log('onWSMessageEvent => chatInfo', chatInfo);
// handling event
};
它记住了什么chatInfo
就在声明的时刻(这是初始渲染)。对于回调来说,值在存储内部和组件渲染范围内更新并不重要,重要的是回调范围以及什么 chatInfo
指的是当你声明回调时。
如果您想创建一个始终可以读取最新状态/属性的回调,您可以保留 chatInfo
在可变引用内。
const { chatInfo } = props;
// 1. create the ref, set the initial value
const chatInfoRef = useRef(chatInfo);
// 2. update the current ref value when your prop is updated
useEffect(() => chatInfoRef.current = chatInfo, [chatInfo]);
// 3. define your callback that can now access the current prop value
const onWSMessageEvent = (event) => {
console.log('onWSMessageEvent => chatInfo', chatInfoRef.current);
};
您可以查看this codesandbox查看使用 ref 和直接使用 prop 之间的区别。
您可以咨询docs about stale props和 useRef docs
从广义上讲,问题在于您试图在范围更窄的组件内管理全局订阅(套接字连接)。
另一个没有 useRef
的解决方案看起来像
useEffect(() => {
socket = services.establishSocketConnection(userId);
socket.addEventListener('message', (message) => handleMessage(message, chatInfo));
return () => {
socket.close();
};
}, [chatInfo]);
在这种情况下,消息事件处理程序通过参数传递必要的信息,并且 useEffect
每次我们获得新的 chatInfo
时,钩子(Hook)都会重新运行.
但是,这可能与您的目标不符,除非您想为每个聊天打开一个单独的套接字,并在每次切换到不同的聊天时关闭该套接字。
因此,“正确的”解决方案需要在项目中向上移动套接字交互。一个提示是您正在使用 userId
打开套接字,这意味着一旦您知道您的 userId
,它就应该运行,一旦用户选择聊天就不会。
要向上移动交互,您可以将传入消息存储在 redux 存储中并将消息传递到 ChatBox
通过 props 组件。或者您可以在 ChatHeads
中创建与套接字的连接组件并将消息向下传递到 ChatBox
。类似的东西
function ChatHeads(props) {
const {
dispatch,
userInfo,
userId
} = props;
const [chatHeads, setChatHeads] = useState([]);
const loadChatHeads = async () => {
const response = await services.getRecentChats(userId, userInfo);
setChatHeads(response.chats);
};
useEffect(() => loadChatHeads(), [userInfo]);
const [messages, setMessages] = useState([]);
useEffect(() => {
socket = services.establishSocketConnection(userId);
socket.addEventListener('message', (msg) => setMessages(messages.concat(msg)));
}, [userId]);
return () => socket.close();
}
return (
// render your current chat and pass the messages as props
)
或者您可以创建一个 reducer 并调度 chatActions.newMessage
事件,然后消息使用 redux 到达当前聊天。
重点是如果你需要chatInfo
打开套接字,然后每次 chatInfo
更改时,您可能必须打开一个新套接字,因此将依赖项添加到 useEffect
是有意义的钩。如果仅取决于userId
,然后将其向上移动到获得 userId
的位置并连接到那里的套接字。
关于javascript - Websocket 事件在 React 应用程序中接收旧的 redux 状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66310269/
我一直在尝试将 redux sagas 和 redux 工具包引入我的项目。我目前遇到的问题是 watcher saga 没有捕捉到 takeEvery 中的调度 Action 。效果并运行处理程序。
我需要使用 deep-freeze 库来深度卡住 react redux 应用程序中的整个 redux 状态,以检查状态是否有任何变化。我应该如何使用 deep-freeze 和 React redu
这是一个关于 Redux js 中状态的问题。我在该州有一个数组列表: { list: list } 根据 Redux 文档,我不应该修改 reducer 中的状态。我想在列表中添加一个新项目。我
我正在构建一个应用程序,在用户向下滚动时执行操作。如果我可以在用户再次向上滚动时撤消这些操作,基本上将滚动变成浏览操作时间线的一种方式,那就太好了。 Redux 中是否有内置的方法来做到这一点?或者我
从我从 Dan Abramov 的蛋头视频“javascript-redux-colocating-selectors-with-reducers”和他的一些推文中了解到,使用选择器将状态映射到 Pr
尝试使用 redux saga 运行 reduxdevtools: 收到此错误: Error Before running a Saga, you must mount the Saga middle
Redux 工具包文档提到在多个 reducer 中使用操作(或者更确切地说是操作类型) First, Redux action types are not meant to be exclusive
Redux 将调度状态更改的操作。 redux 中 Action 类型的命名约定是什么? 最佳答案 社区中有一些约定,我将在这里列出我知道并认为有用的约定: 最常见的约定是 将 Action 类型(“
使用 Redux Toolkit 可以吗,即使我只在其中创建 Slice 并通过 Redux Saga 解决中间件问题? 或者在这种情况下,最佳实践是使用 Redux Saga + raw Redux
Redux 如何处理深度嵌套的叶子模型变更?意思是,我正在从叶子一直发送到它的 reducer 句柄的更改事件,并且我不想将更改事件广播到整个树。 最佳答案 在 Redux 中,所有操作总是被分派(d
redux 使用什么类型的数据结构来使数据在 Angular 和 React.js 中持久化?我假设它使用持久数据结构。 最佳答案 Redux 是一种用于管理状态的架构。它不使用任何数据结构。它保留您
我们正在计划一个 Electron 应用程序,并且我们正在考虑 Redux。该应用程序将具有巨大 状态,可能会从数十个或数百个文件中读取数据。在做一些了解 Redux 的研究时,我发现 reducer
我不想添加属性 sections: []到我的对象 formOpen在 reducer 中,我收到我的对象 formOpen从我的服务器和其他属性,我想添加这个,我该怎么做? 谢谢 import {
我使用 redux-saga 的主要原因之一是它进行异步函数调用的可测试性。我的困境是,当我使用不属于我的 redux 存储的有状态对象进行编程时,使用 sagas 进行编程变得非常尴尬。是否有使用非
我是 redux 的新手,所以我有几个问题希望得到解答。如果您能解释一些有关构建 redux 架构的内容,那就太好了。 此时我使用 Flutter_Redux 包 ( https://pub.dart
我正在使用 React + Flux。我们的团队正计划从 flux 转向 redux。来自 Flux 世界的我对 Redux 感到非常困惑。在 flux 控制流中很简单,从组件 -> 操作 -> 存储
这个问题与过去不同,这就是为什么。这个问题是什么时候。由于两者本身都是很好的框架,所以问题是我什么时候应该使用 thunk 而不是 saga。因为我的一位 friend 一直坚持让我在我们的应用程序中
我搜索了高低,但找不到明确的答案。 我已经设法绕开 Redux 的机制,但是当我谈到 API 调用和异步操作创建者时,我被 Promises 上下文中的中间件所困。 你能帮我把乱七八糟的东西弄好吗?
我正在使用 redux-saga 但遇到了一个问题:redux-auth-wrapper 需要 redux-thunk进行重定向,所以我只是在我的商店中添加了 thunk: import {creat
问题(tl;博士) 我们如何创建 custom redux-orm reducer与 redux-toolkit的createSlice ? 有没有比这个问题中提供的尝试更简单、推荐、更优雅或只是其他
我是一名优秀的程序员,十分优秀!