【问题标题】:Setstate provided by the context is not working上下文提供的 Setstate 不起作用
【发布时间】:2021-07-18 07:57:26
【问题描述】:

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

MenuBar.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 将数组提供给多个组件。菜单栏中的生成新数组按钮使数组随机化。

问题是当我点击 generate-array 按钮时,它会随机化数组,但 setArray 方法不会更新状态。

任何帮助将不胜感激。 提前致谢。

【问题讨论】:

  • 所以你是说setArray(resetArray(array)) 实际上并没有更新状态?你能分享这个resetArray 实用程序吗?

标签: javascript reactjs typescript react-context


【解决方案1】:

可能你修改了数组并且对对象的引用保持不变,所以 React 无法知道你更新了它。

试试看,如果有效,你需要修改 resetArray helper 以返回一个新数组

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

【讨论】:

  • 我想你的意思是setArray(resetArray([...array]))setArray(resetArray(array.slice()))
  • setArray(resetArray([...array])) 这也应该有效
【解决方案2】:

好吧,我怀疑你只是在改变当前状态对象,而不是通过这个 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);

【讨论】:

    猜你喜欢
    • 2020-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多