上下文提供的Setstate不起作用



App.tsx

import React from 'react';
import Visualizer from './components/Visualizer/Visualizer';
import ArrayProvider from './contexts/arrayProvider';
function App() {
return (
<ArrayProvider>
<Visualizer />
</ArrayProvider>
);
}
export default App;

Visualizer.tsx

import React, { useEffect } from 'react'
import MenuBar from '../MenuBar/MenuBar'
import { useArray } from '../../contexts/arrayProvider'
import './Visualizer.min.css'
import { resetArray } from '../../utils/helpers'
function Visualizer() {
const { array, setArray } = useArray()
useEffect(() => {
console.log("Visualizer mounted!")
setArray(resetArray(array))
}, [])
return (
<div className="visualizer">
<MenuBar />
{array.map((num, idx) => <div key={idx}>{idx}: {num} </div>)}
</div>
)
}
export default Visualizer;

arrayProvider.tsx

import React, { useContext, createContext, useState, Dispatch, SetStateAction } from "react";
import { ARRAY_LENGTH, generateArray } from "../utils/helpers";
export interface IFC_ProviderProps {
children?: any
}
type ArrayContextData = number[]
type ArrayContextValue = {
array: ArrayContextData;
setArray: Dispatch<SetStateAction<ArrayContextData>>;
}
export const ArrayContext = createContext<ArrayContextValue | undefined>(undefined)
const ArrayProvider = (props: IFC_ProviderProps) => {
const [array, setArray] = useState(generateArray(ARRAY_LENGTH))
return (
<ArrayContext.Provider value={{ array, setArray }}>
{props.children}
</ArrayContext.Provider>
)
}
export const useArray = () => {
const ctxValue = useContext(ArrayContext)
if (ctxValue === undefined) throw new Error(
"Expected an AppProvider somewhere in the react tree to set context value")
return ctxValue // now has type AppContextValue
// or even provide domain methods for better encapsulation
}
export default ArrayProvider

菜单栏.tsx

import React from 'react'
import { useArray } from '../../contexts/arrayProvider'
import { resetArray } from '../../utils/helpers'
import './MenuBar.min.css'
export default function MenuBar() {
const { array, setArray } = useArray()
console.log("Rendering Menubar")
const generateNewArray = () => {
console.log("Generating...")
setArray(resetArray(array))
}
return (
<div className="menu-bar">
<button
className="generate-new-array-btn"
onClick={generateNewArray}
>Generate New Array</button>
</div>
)
}

我正在尝试创建一个排序可视化工具。我正在使用上下文API将数组提供给几个组件。菜单栏中的生成新数组按钮会使数组随机化。

问题是,当我单击生成数组按钮时,它确实会随机化数组,但setArray方法不会更新状态。

如有任何帮助,我们将不胜感激。提前谢谢。

可能您在适当的位置修改了数组,并且对对象的引用保持不变,所以React不知道您更新了它。

试试看,如果它有效,你需要修改resetArrayhelper来返回一个新的数组

const generateNewArray = () => {
console.log("Generating...")
setArray([...resetArray(array)])
}

好吧,我怀疑您只是在更改当前状态对象,而不是通过这个resetArray实用程序返回新的引用。

由于更新数组或包含数组的状态,您通常希望使用函数状态更新来从以前的状态进行更新,而不仅仅是在回调范围中关闭的任何状态。

setArray(array => resetArray(array));

您还需要确保resetArray实用程序不会改变传递给它的内容。使用React状态更新,您通常会对正在更新的状态进行浅层复制,避免突变的实用程序函数也是如此。在resetArray实用程序中,您将希望首先浅层复制传递的数组参数,然后应用任何重置逻辑。

const resetArray = array => {
const nextArray = array.slice();
// ... apply resetting logic against nextArray
return nextArray;
};

如果array的状态值与resetArray的函数签名匹配(即相同的arg编号和类型匹配(,则可以直接传递resetArray函数,避免匿名函数。

setArray(resetArray);

最新更新