[英]React useState array update problem via context
I have an array that via useState hook, I try to add elements to the end of this array via a function that I make available through a context.我有一个通过 useState 钩子的数组,我尝试通过我通过上下文提供的 function 将元素添加到该数组的末尾。 However the array never gets beyond length 2, with elements [0, n] where n is the last element that I pushed after the first.然而,数组永远不会超过长度 2,元素 [0, n] 其中 n 是我在第一个元素之后推送的最后一个元素。
I have simplified this a bit, and haven't tested this simple of code, it isn't much more complicated though.我已经简化了一点,并没有测试过这么简单的代码,但它并没有复杂多少。
MyContext.tsx MyContext.tsx
interface IElement = {
title: string;
component: FunctionComponent<any>;
props: any;
}
interface IMyContext = {
history: IElement[];
add: <T>(title: string, component: FunctionComponent<T>, props: T) => void
}
export const MyContext = React.createContext<IMyContext>({} as IMyContext)
export const MyContextProvider = (props) => {
const [elements, setElements] = useState<IElement[]>([]);
const add = <T extends any>(title: string, component: FunctionComponent<T>, props: T) => {
setElements(elements.concat({title, component, props}));
}
return (
<MyContext.Provider values={{elements, add}}>
{props.children}
</MyContext.Provider>
);
}
In other elements I use this context to add elements and show the current list of elements, but I only ever get 2, no matter how many I add.在其他元素中,我使用此上下文添加元素并显示当前元素列表,但无论添加多少,我都只会得到 2 个。
I add via onClick from various elements and I display via a sidebar that uses the components added.我通过 onClick 从各种元素中添加,并通过使用添加的组件的侧边栏显示。
SomeElement.tsx一些元素.tsx
const SomeElement = () => {
const { add } = useContext(MyContext);
return (
<Button onClick=(() => {add('test', MyDisplay, {id: 42})})>Add</Button>
);
};
DisplayAll.tsx DisplayAll.tsx
const DisplayAll = () => {
const { elements } = useContext(MyContext);
return (
<>
{elements.map((element) => React.createElement(element.component, element.props))}
</>
);
};
It sounds like your issue was in calling add
multiple times in one render.听起来您的问题是在一次渲染中多次调用add
。 You can avoid adding a ref as in your currently accepted answer by using the callback version of setState:通过使用 setState 的回调版本,您可以避免在当前接受的答案中添加 ref:
const add = <T extends any>(title: string, component: FunctionComponent<T>, props: T) => {
setElements(elements => elements.concat({title, component, props}));
};
With the callback version, you'll always be sure to have a reference to the current state instead of a value in your closure that may be stale.使用回调版本,您将始终确保引用当前的 state 而不是闭包中可能陈旧的值。
The below may help if you're calling add multiple times within the same render:如果您在同一个渲染中多次调用 add ,以下内容可能会有所帮助:
interface IElement = {
title: string;
component: FunctionComponent<any>;
props: any;
}
interface IMyContext = {
history: IElement[];
add: <T>(title: string, component: FunctionComponent<T>, props: T) => void
}
export const MyContext = React.createContext<IMyContext>({} as IMyContext)
export const MyContextProvider = (props) => {
const [elements, setElements] = useState<IElement[]>([]);
const currentElements = useRef(elements);
const add = <T extends any>(title: string, component: FunctionComponent<T>, props: T) => {
currentElements.current = [...currentElements.current, {title, component, props}];
setElements(currentElements.current);
}
return (
<MyContext.Provider values={{history, add}}>
{props.children}
</MyContext.Provider>
);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.