使用 useState 更新对象并不是更新

问题描述 投票:0回答:1

我有一个 React 上下文,它将在一个对象中为我保存大量文件名列表。每个文件名数组都将与给定的

camId
相关联。

因此,水合后,filenamesObj 应如下所示:

{
cam1: [file1, file2, file3]
cam2: [filea, fileb, filec]
//    etc...
}

这是上下文和提供者的代码:

export const FilenamesContext = createContext()

export const FilenamesProvider = ({ children }) => {
    const [filenamesObj, setFilenamesObj] = useState({})

    const addFilenames = ({ camId, incomingFilenamesArr }) => {
        let newFilenamesArr
        if (filenamesObj[camId]) {
            newFilenamesArr = combineAndSortArrays(filenamesObj[camId], incomingFilenamesArr)
        } else {
            newFilenamesArr = incomingFilenamesArr
        }
        console.log('newFilenamesArr :>> ', newFilenamesArr); // THIS PRINTS THE CORRECT VALUE

        setFilenamesObj({ ...filenamesObj, [camId]: newFilenamesArr })
    }

    return (
        <FilenamesContext.Provider
            value={{
                filenamesObj,
                addFilenames,
            }}
        >
            {children}
        </FilenamesContext.Provider>
    )
}

然后我将其放入反应组件中,它实际上只是显示文件名 - 这是一个概念验证:

export default function CameraDetails() {
    let { camId } = useParams()
    let { filenamesObj } = useFilenames()

    return (
        <>
            <FilenamesLoader camId={camId} />
            <Typography>Cam file names {camId}</Typography>

            {JSON.stringify(filenamesObj)}

            <Link to={"/"}>Go HOME</Link>
        </>
    )
}

注意,

filenamesLoader
组件应该进行 API 调用并通过 addFilenames 函数(上面定义)将结果加载到 FilenamesContext 中:

export default function CameraLoader({ camId }) {
    const { filenamesObj, addFilenames } = useContext(FilenamesContext)

    useEffect(() => {
        async function getAllFilenames(camId, before, count = 1) {
            if (count > 5) {
                console.log("count reached 5") // keeps this from being an infinite loop
                return
            }
            let returnedFilenames = await api.getFilenames({ camId, before })
            addFilenames({ camId, incomingFilenamesArr: returnedFilenames })

            await getAllFilenames(camId, getDateFromFilename(returnedFilenames[returnedFilenames.length - 1]), count + 1)
        }

        getAllFilenames(camId)
    }, [])

    return null
    }

但是,问题:是存储在上下文中的

filenamesObj
似乎永远不会记住该值...它显示第一个调用的值...更新以显示第二个调用的值.. .然后是第三个...最后,它总是只显示第 5 个 API 调用的值...而不是 5 个单独调用的组合。

我的猜想是上下文中的

filenamesObj
没有被更新(或者我正在使用它的“陈旧”值),因此
setFilenamesObj({ ...filenamesObj, [camId]: newFilenamesArr })
实际上只是“传播”一个空对象而不是一个对象有价值观。

帮忙?

reactjs react-hooks react-context
1个回答
0
投票

问题在于,通过递归调用该函数,会以陈旧状态调用该函数。

我将 addFilenames 函数更改为使用“prevState”的函数调用。新的工作函数如下所示:

const addFilenames = ({ camId, incomingFilenamesArr }) => {
        setFilenamesObj((prevFilenamesObj) => {
            let newFilenamesArr
            if (prevFilenamesObj[camId]) {
                newFilenamesArr = combineAndSortArrays(prevFilenamesObj[camId], incomingFilenamesArr)
            } else {
                newFilenamesArr = incomingFilenamesArr
            }

            return { ...prevFilenamesObj, [camId]: newFilenamesArr }
        })
    }

感谢@G Gallegos在这里回答:为什么需要带有功能更新表单的React useState?让我到达正确的地方

© www.soinside.com 2019 - 2024. All rights reserved.