javascript - 为什么我的 React Context Helper 函数使用过时的状态?
问题描述
谢谢你看这个...
这是我的问题;在我的 react native 应用程序中,我编写了一个 React Context 来管理“标题消息”,我可以在代码库中的任何位置调用它,并在我的应用程序的 Header 元素下附加一条消息(全局显示)。这个过程有效,我可以使用辅助函数 .addNewMessage('id', 'JSX.Element'); 呈现我添加的第一个标题消息。但是当我再次调用它时;上一条消息被删除并显示新消息...
我相信这种情况正在发生,因为在下面共享的上下文中定义的函数 .addNewMessage() 引用状态...调用它会更新状态...然后再次调用它;它仍然引用原始状态...查看控制台日志以了解这如何在随后的两个调用中发挥作用。
上下文背后的代码;辅助函数在函数中声明...
import * as React from 'react';
import { Text } from 'react-native';
export interface IElements {
[key: string] : JSX.Element;
}
export interface IState {
setState : (newState: IState) => void;
addNewMessage : (id: string, elem: JSX.Element) => void;
removeMessage : (id: string) => void;
returnAllMessages : () => JSX.Element[]
messages : IElements;
}
export interface IProps {
children : JSX.Element[] | JSX.Element;
}
const defaultValues: IState = {
setState: () => undefined,
addNewMessage: () => undefined,
removeMessage: () => undefined,
returnAllMessages: () => [],
messages : {'test1': <Text>FooBarLoremIpsum</Text>},
};
export const HeaderMessagesContext: React.Context<IState> = React.createContext<IState>(defaultValues);
const CTX_HeaderMessages: React.FC<IProps> = (props: IProps) => {
const [state, updateState] = React.useState(defaultValues);
// Every time I call this function, it is acting like it is using
// defaultValues instead of state... I assume this is a weird side effect
// of defining a function then storing an instance of that function inside
// the state object itself...? But anytime I try and declare a side effect
// that would essentially store a new instance of the function; I find myself
// in an infinite Loop... I'm struggling with the pattern here to make this work :/
const addNewMessage = (id: string, elem : JSX.Element) => {
console.log('State Coming into "AddNewMessage"', state);
const newMessages = {...state.messages};
newMessages[id] = elem;
console.log('State Exiting "AddNewMessage"', {...state, messages : newMessages});
updateState({...state, messages : newMessages});
};
const removeMessage = (id: string) => { if(state.messages[id]) {delete state.messages[id]} }
const returnAllMessages = () => Object.keys(state.messages).map(key => state.messages[key]);
const val: IState = {
...state,
setState : updateState,
addNewMessage,
removeMessage,
returnAllMessages
}
return (
<HeaderMessagesContext.Provider value={val}>
{props.children}
</HeaderMessagesContext.Provider>
);
};
export default CTX_HeaderMessages;
Chrome 控制台日志
这些日志显示了我正在经历的事情......我想提请您注意消息对象的价值。当我第一次调用该函数时;增值;当我第二次调用该函数时;请注意,第一次调用的值(在上一行)不存在...
State Comming into "AddNewMessage"
{messages: {…}, setState: ƒ, addNewMessage: ƒ, removeMessage: ƒ, returnAllMessages: ƒ}
addNewMessage: ƒ addNewMessage()
messages: {test1: {…}}
removeMessage: ƒ removeMessage()
returnAllMessages: ƒ returnAllMessages()
setState: ƒ setState()
__proto__: Object
HeaderMessages.tsx:38 State Exiting "AddNewMessage"
{messages: {…}, setState: ƒ, addNewMessage: ƒ, removeMessage: ƒ, returnAllMessages: ƒ}
addNewMessage: ƒ addNewMessage()
messages: {test1: {…}, SuggestUpdate_Line78: {…}}
removeMessage: ƒ removeMessage()
returnAllMessages: ƒ returnAllMessages()
setState: ƒ setState()
__proto__: Object
HeaderMessages.tsx:35 State Comming into "AddNewMessage"
{messages: {…}, setState: ƒ, addNewMessage: ƒ, removeMessage: ƒ, returnAllMessages: ƒ}
addNewMessage: ƒ addNewMessage()
messages: {test1: {…}}
removeMessage: ƒ removeMessage()
returnAllMessages: ƒ returnAllMessages()
setState: ƒ setState()
__proto__: Object
HeaderMessages.tsx:38 State Exiting "AddNewMessage"
{messages: {…}, setState: ƒ, addNewMessage: ƒ, removeMessage: ƒ, returnAllMessages: ƒ}
addNewMessage: ƒ addNewMessage()
messages: {test1: {…}, SuggestUpdate_Line79: {…}}
removeMessage: ƒ removeMessage()
returnAllMessages: ƒ returnAllMessages()
setState: ƒ setState()
__proto__: Object
解决方案
我认为在您的上下文中传递 setState 是多余的。您只需要将消息存储在您的状态中,而不是 CRUD 方法。看看下面的代码,我认为它会工作。
import * as React from 'react';
import { Text } from 'react-native';
export interface IElements {
[key: string] : JSX.Element;
}
export interface IState {
addNewMessage : (id: string, elem: JSX.Element) => void;
removeMessage : (id: string) => void;
returnAllMessages : () => JSX.Element[]
messages : IElements;
}
export interface IProps {
children : JSX.Element[] | JSX.Element;
}
const defaultValues: IState = {
addNewMessage: () => undefined,
removeMessage: () => undefined,
returnAllMessages: () => [],
messages: { test1: <Text>FooBarLoremIpsum</Text> },
};
const defaultMessages : IElements = {
messages: { test1: <Text>FooBarLoremIpsum</Text> },
};
export const HeaderMessagesContext: React.Context<IState> = React.createContext<IState>(defaultValues);
const CTX_HeaderMessages: React.FC<IProps> = (props: IProps) => {
const [state, updateState] = React.useState<IElements>(defaultMessages);
// Every time I call this function, it is acting like it is using
// defaultValues instead of state... I assume this is a weird side effect
// of defining a function then storing an instance of that function inside
// the state object itself...? But anytime I try and declare a side effect
// that would essentially store a new instance of the function; I find myself
// in an infinite Loop... I'm struggling with the pattern here to make this work :/
const addNewMessage = (id: string, elem : JSX.Element) => {
console.log('State Coming into "AddNewMessage"', state);
const newMessages = { ...state };
newMessages[id] = elem;
console.log('State Exiting "AddNewMessage"', newMessages);
updateState(newMessages);
};
const removeMessage = (id: string) => { if (state[id]) { delete state[id]; } };
const returnAllMessages = () => Object.keys(state).map((key) => state[key]);
const val: IState = {
messages: state,
addNewMessage,
removeMessage,
returnAllMessages,
};
return (
<HeaderMessagesContext.Provider value={val}>
{props.children}
</HeaderMessagesContext.Provider>
);
};
export default CTX_HeaderMessages;
推荐阅读
- java - 为 Imageview NOT SRC 的背景绘制着色
- python - Python OpenCV2 网络摄像头 - 捕获的黑色图像
- filter - 是否有任何功能可以根据 Tableau CRM 中的过滤器更改动态更改列名
- excel - 检查范围内单元格的一部分是否包含出现在另一个范围内的文本的功能?
- neovim - Neovim lsp 自动修复/修复当前?
- javascript - 使用反应形式预选材料单选按钮不起作用
- swift - 顶级语句不能以闭包表达式开头
- c++ - 给定点,计算法线并在 CGAL 中执行多边形表面重建
- python - 绘制关于 x 轴值比例的图
- php - 如何在 Symfony5 项目中重定向到公共目录中的静态页面