上下文挂钩不能存储值
context hook cant store value
下面的代码工作正常,除非调用 Add
函数将新数字添加到数组,
数组仅包含最后添加的项目。
不明白为什么它不存储 ID
App.ts
import MyComponent from "./main";
import { FavoriteContext, usePostsContextValue } from "./store";
function App() {
const postsContextValue = usePostsContextValue();
return (
<FavoriteContext.Provider value={postsContextValue}>
<MyComponent />
</Container>
</FavoriteContext.Provider>
);
}
export default App;
组件:
import { FavoriteContext } from "../store";
...
function MyComponent() {
const [data, setData] = useState<certificates[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [pageNumber, setPageNumber] = useState<number>(1);
const { IDs, Add, Remove } = useContext(FavoriteContext);
useEffect(() => {
console.log("IDs", IDs); //logs only 1 item, last selected Id
}, [IDs]);
const handleAddClick= async (id: number) => {
Add(id);
};
const columns: TableColumn<certificates>[] = useMemo(() => {
return [
{
name: "STATUS",
cell: (row) => <strong>{status(row.status)}</strong>,
},
{
cell: (row) => {
return (
<IconButton onClick={() => handleAddClick(row.id)}>
<BookmarkBorderIcon />
</IconButton>
);
},
button: true,
},
];
}, []);
return (
<DataTable
columns={columns}
data={data}
pagination
paginationServer
paginationTotalRows={totalRows}
onChangeRowsPerPage={handlePerRowsChange}
onChangePage={handlePageChange}
/>
);
}
export default MyComponent;
Context.ts:
import React, { useCallback, useMemo, useState } from "react";
import { favouriteType } from "../models";
export const defaultValue: favouriteType = {
IDs: [],
Add: (id: number) => {},
Remove: (id: number) => {},
};
export const FavoriteContext = React.createContext<favouriteType>(defaultValue);
function usePostsContextValue(): favouriteType {
const [IDs, setIDs] = useState<number[]>([]);
const Add = (id: number) => {
setIDs([...IDs, id]);
};
const Remove = (id: number) => {
const newPosts = [...IDs];
const removedPostIndex = newPosts.findIndex((f) => f === id);
if (removedPostIndex > -1) {
newPosts.splice(removedPostIndex, 1);
}
setIDs(newPosts);
};
return {
IDs,
Add,
Remove,
};
}
export { usePostsContextValue };
每次添加新 ID 时,都会创建一个新的 Add
函数来捕获新 ID 的值。
const Add = (id: number) => {
setIDs([...IDs, id]); // <-- this capture the ID of the outer scope
};
这按预期工作,但是查看下面的组件:
const columns: TableColumn<certificates>[] = useMemo(() => {
return [
{
name: "STATUS",
cell: (row) => <strong>{status(row.status)}</strong>,
},
{
cell: (row) => {
return (
<IconButton onClick={() => handleAddClick(row.id)}>
<BookmarkBorderIcon />
</IconButton>
);
},
button: true,
},
];
}, []);
由于此组件永远不会重新呈现,因此 Add
函数不会更新,因此它始终是捕获的 IDs
为空 []
的第一个版本。因此添加一个 ID 总是:
const Add = (id: number) => {
setIDs([...[], id]); // the first vesion of Add captured IDs = [];
};
并且始终只有最后一个 ID。
解决方案是包含 handleAddClick
(它捕获 useMemo dep 数组中的新 Add
函数:
const columns: TableColumn<certificates>[] = useMemo(() => {
return [
{
name: "STATUS",
cell: (row) => <strong>{status(row.status)}</strong>,
},
{
cell: (row) => {
return (
<IconButton onClick={() => handleAddClick(row.id)}>
<BookmarkBorderIcon />
</IconButton>
);
},
button: true,
},
];
}, [handleAddClick]);
然而,这破坏了 useMemo
的目的,因为 Add
/handleAddClick
总是在每次渲染时重新创建,所以解决方案是将它们都包装在 useCallback
中.
const Add = useCallback((id: number) => {
setIDs([...IDs, id]);
}, [IDs]); // notice I have to include IDs here so that the function can be recreated with the new IDs.
const handleAddClick= useCallback(async (id: number) => {
Add(id);
}, []);
更好的是,您可以使用 setState
的函数语法,这样就无需在 dep 数组中包含 IDs
,从而提高性能。
const Add = useCallback((id: number) => {
setIDs((prevIDs) => [...prevIDs, id]); // the function form will receive the previous state as the argument.
}, []);
下面的代码工作正常,除非调用 Add
函数将新数字添加到数组,
数组仅包含最后添加的项目。
不明白为什么它不存储 ID
App.ts
import MyComponent from "./main";
import { FavoriteContext, usePostsContextValue } from "./store";
function App() {
const postsContextValue = usePostsContextValue();
return (
<FavoriteContext.Provider value={postsContextValue}>
<MyComponent />
</Container>
</FavoriteContext.Provider>
);
}
export default App;
组件:
import { FavoriteContext } from "../store";
...
function MyComponent() {
const [data, setData] = useState<certificates[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [pageNumber, setPageNumber] = useState<number>(1);
const { IDs, Add, Remove } = useContext(FavoriteContext);
useEffect(() => {
console.log("IDs", IDs); //logs only 1 item, last selected Id
}, [IDs]);
const handleAddClick= async (id: number) => {
Add(id);
};
const columns: TableColumn<certificates>[] = useMemo(() => {
return [
{
name: "STATUS",
cell: (row) => <strong>{status(row.status)}</strong>,
},
{
cell: (row) => {
return (
<IconButton onClick={() => handleAddClick(row.id)}>
<BookmarkBorderIcon />
</IconButton>
);
},
button: true,
},
];
}, []);
return (
<DataTable
columns={columns}
data={data}
pagination
paginationServer
paginationTotalRows={totalRows}
onChangeRowsPerPage={handlePerRowsChange}
onChangePage={handlePageChange}
/>
);
}
export default MyComponent;
Context.ts:
import React, { useCallback, useMemo, useState } from "react";
import { favouriteType } from "../models";
export const defaultValue: favouriteType = {
IDs: [],
Add: (id: number) => {},
Remove: (id: number) => {},
};
export const FavoriteContext = React.createContext<favouriteType>(defaultValue);
function usePostsContextValue(): favouriteType {
const [IDs, setIDs] = useState<number[]>([]);
const Add = (id: number) => {
setIDs([...IDs, id]);
};
const Remove = (id: number) => {
const newPosts = [...IDs];
const removedPostIndex = newPosts.findIndex((f) => f === id);
if (removedPostIndex > -1) {
newPosts.splice(removedPostIndex, 1);
}
setIDs(newPosts);
};
return {
IDs,
Add,
Remove,
};
}
export { usePostsContextValue };
每次添加新 ID 时,都会创建一个新的 Add
函数来捕获新 ID 的值。
const Add = (id: number) => {
setIDs([...IDs, id]); // <-- this capture the ID of the outer scope
};
这按预期工作,但是查看下面的组件:
const columns: TableColumn<certificates>[] = useMemo(() => {
return [
{
name: "STATUS",
cell: (row) => <strong>{status(row.status)}</strong>,
},
{
cell: (row) => {
return (
<IconButton onClick={() => handleAddClick(row.id)}>
<BookmarkBorderIcon />
</IconButton>
);
},
button: true,
},
];
}, []);
由于此组件永远不会重新呈现,因此 Add
函数不会更新,因此它始终是捕获的 IDs
为空 []
的第一个版本。因此添加一个 ID 总是:
const Add = (id: number) => {
setIDs([...[], id]); // the first vesion of Add captured IDs = [];
};
并且始终只有最后一个 ID。
解决方案是包含 handleAddClick
(它捕获 useMemo dep 数组中的新 Add
函数:
const columns: TableColumn<certificates>[] = useMemo(() => {
return [
{
name: "STATUS",
cell: (row) => <strong>{status(row.status)}</strong>,
},
{
cell: (row) => {
return (
<IconButton onClick={() => handleAddClick(row.id)}>
<BookmarkBorderIcon />
</IconButton>
);
},
button: true,
},
];
}, [handleAddClick]);
然而,这破坏了 useMemo
的目的,因为 Add
/handleAddClick
总是在每次渲染时重新创建,所以解决方案是将它们都包装在 useCallback
中.
const Add = useCallback((id: number) => {
setIDs([...IDs, id]);
}, [IDs]); // notice I have to include IDs here so that the function can be recreated with the new IDs.
const handleAddClick= useCallback(async (id: number) => {
Add(id);
}, []);
更好的是,您可以使用 setState
的函数语法,这样就无需在 dep 数组中包含 IDs
,从而提高性能。
const Add = useCallback((id: number) => {
setIDs((prevIDs) => [...prevIDs, id]); // the function form will receive the previous state as the argument.
}, []);