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);