反应上下文不保持数据状态
React context not keeping data in state
我正在尝试使用 React 上下文来替换我实际的 Redux。
我想使用此上下文来存储文件数组。
这是一个 nextjs 应用程序,我不知道它会导致一些问题
我有我的FileContextProvider
import { createContext, useState, useEffect } from "react";
export const FileContext = createContext({});
export function FileContextProvider({ children }) {
const [files, setFiles] = useState([]);
useEffect(() => {
console.log('files', files);
}, [files])
const addLocalFiles = (newFiles, mode) => {
console.log('addLocalFiles', files);
setFiles([...files].concat(newFiles));
}
return (
<FileContext.Provider value={{
files,
addLocalFiles
}} >
{children}
</FileContext.Provider>
);
}
然后我创建了一个全局上下文,我想在其中初始化我所有的上下文,目前我只有一个文件。
import { FileContextProvider } from "./file";
export default function Context({ children }) {
return (
<FileContextProvider>
{children}
</FileContextProvider>
);
}
然后我在_app.js
中添加上下文
import Context from '../context';
function MyApp({ Component, pageProps }) {
return (
<Context>
<Component {...pageProps} />
</Context>
)
}
export default MyApp;
在我的一个子组件中我有
import { FileContext } from '../../context/file';
export default function TopBlock({ type, format }) {
return (
<div className="col-12 col-lg-8 offset-lg-2">
<FileContext.Consumer>
{({ files, addLocalFiles, removeFile, updateFile }) => (
<UploadBlock files={files} addLocalFiles={addLocalFiles} />
)}
</FileContext.Consumer>
</div>
);
}
这是我的 UploadBlock
import React, { useCallback, useRef } from 'react';
import { useDropzone } from 'react-dropzone';
export default function UploadBlock({ files, addLocalFiles }) {
const dropzoneParent = useRef(null);
function MyDropzone() {
const onDrop = useCallback(async acceptedFiles => {
addLocalFiles(acceptedFiles)
}, [])
const dropOptions = { onDrop }
const { getRootProps, getInputProps, isDragActive } = useDropzone(dropOptions)
return (
<div {...getRootProps()} ref={dropzoneParent}>
<input {...getInputProps()} />
<div>Drop Here</div>
</div>
)
}
return (
<div>
{MyDropzone()}
</div>
)
}
在我的 UploadBlock
中,当我调用 addLocalFiles
它正在工作时,我的 files
变量包含我的新文件,但是如果我第二次调用 addLocalFiles
前一个FileContextProvider
中不存在文件,console.log('addLocalFiles', files);
返回空数组。
useEffect
只是调试用的,每次调用addLocalFiles
都会触发,新文件打印好。
我不明白为什么files
在回调的时候状态变成空数组addLocalFiles
我只有一个 Context
和 FileContext.Consumer
我不知道它是否有任何变化
请提供您的组件,以便我们确定您如何使用所需参数调用 addLocalFiles
方法。
我也认为没有必要传播 [...files].concat(newfile) 而不是 files.concat(newfile)
在 React 中,states
依赖于特定的渲染。这意味着,每个渲染器都会有自己的 states
。因此,在声明 addLocalFiles
时,特定的 files
状态取决于渲染。
const addLocalFiles = (newFiles, mode) => {
console.log('addLocalFiles', files);
setFiles([...files].concat(newFiles)); // state `files` are used
}
我认为问题可能是你用 useCallback
.
包装了 addLocalFiles
函数
const onDrop = useCallback(async acceptedFiles => {
addLocalFiles(acceptedFiles)
}, []) // empty dependency, so it will always referencing same `addLocalFiles` function.
addLocalFiles
永远不会再生成,即使它渲染了。因此,更改后的状态 files
不会应用于 addLocalFiles
。
如果你想防止无用的re-render,你应该指定它的依赖,files
.
const onDrop = useCallback(async acceptedFiles => {
addLocalFiles(acceptedFiles, mode)
}, [addLocalFiles]); // this function is dependent on `files`
或者您可以跳过 useCallback
,如果优化不是真的必要的话。我发现了一个 问题可以帮助您更好地理解。
我正在尝试使用 React 上下文来替换我实际的 Redux。 我想使用此上下文来存储文件数组。 这是一个 nextjs 应用程序,我不知道它会导致一些问题
我有我的FileContextProvider
import { createContext, useState, useEffect } from "react";
export const FileContext = createContext({});
export function FileContextProvider({ children }) {
const [files, setFiles] = useState([]);
useEffect(() => {
console.log('files', files);
}, [files])
const addLocalFiles = (newFiles, mode) => {
console.log('addLocalFiles', files);
setFiles([...files].concat(newFiles));
}
return (
<FileContext.Provider value={{
files,
addLocalFiles
}} >
{children}
</FileContext.Provider>
);
}
然后我创建了一个全局上下文,我想在其中初始化我所有的上下文,目前我只有一个文件。
import { FileContextProvider } from "./file";
export default function Context({ children }) {
return (
<FileContextProvider>
{children}
</FileContextProvider>
);
}
然后我在_app.js
import Context from '../context';
function MyApp({ Component, pageProps }) {
return (
<Context>
<Component {...pageProps} />
</Context>
)
}
export default MyApp;
在我的一个子组件中我有
import { FileContext } from '../../context/file';
export default function TopBlock({ type, format }) {
return (
<div className="col-12 col-lg-8 offset-lg-2">
<FileContext.Consumer>
{({ files, addLocalFiles, removeFile, updateFile }) => (
<UploadBlock files={files} addLocalFiles={addLocalFiles} />
)}
</FileContext.Consumer>
</div>
);
}
这是我的 UploadBlock
import React, { useCallback, useRef } from 'react';
import { useDropzone } from 'react-dropzone';
export default function UploadBlock({ files, addLocalFiles }) {
const dropzoneParent = useRef(null);
function MyDropzone() {
const onDrop = useCallback(async acceptedFiles => {
addLocalFiles(acceptedFiles)
}, [])
const dropOptions = { onDrop }
const { getRootProps, getInputProps, isDragActive } = useDropzone(dropOptions)
return (
<div {...getRootProps()} ref={dropzoneParent}>
<input {...getInputProps()} />
<div>Drop Here</div>
</div>
)
}
return (
<div>
{MyDropzone()}
</div>
)
}
在我的 UploadBlock
中,当我调用 addLocalFiles
它正在工作时,我的 files
变量包含我的新文件,但是如果我第二次调用 addLocalFiles
前一个FileContextProvider
中不存在文件,console.log('addLocalFiles', files);
返回空数组。
useEffect
只是调试用的,每次调用addLocalFiles
都会触发,新文件打印好。
我不明白为什么files
在回调的时候状态变成空数组addLocalFiles
我只有一个 Context
和 FileContext.Consumer
我不知道它是否有任何变化
请提供您的组件,以便我们确定您如何使用所需参数调用 addLocalFiles
方法。
我也认为没有必要传播 [...files].concat(newfile) 而不是 files.concat(newfile)
在 React 中,states
依赖于特定的渲染。这意味着,每个渲染器都会有自己的 states
。因此,在声明 addLocalFiles
时,特定的 files
状态取决于渲染。
const addLocalFiles = (newFiles, mode) => {
console.log('addLocalFiles', files);
setFiles([...files].concat(newFiles)); // state `files` are used
}
我认为问题可能是你用 useCallback
.
addLocalFiles
函数
const onDrop = useCallback(async acceptedFiles => {
addLocalFiles(acceptedFiles)
}, []) // empty dependency, so it will always referencing same `addLocalFiles` function.
addLocalFiles
永远不会再生成,即使它渲染了。因此,更改后的状态 files
不会应用于 addLocalFiles
。
如果你想防止无用的re-render,你应该指定它的依赖,files
.
const onDrop = useCallback(async acceptedFiles => {
addLocalFiles(acceptedFiles, mode)
}, [addLocalFiles]); // this function is dependent on `files`
或者您可以跳过 useCallback
,如果优化不是真的必要的话。我发现了一个