我正在使用 React 和 Context API(useContext 挂钩)制作 Google Keep Clone。一切都进行得非常顺利,一切都按正确的顺序进行,直到我想到以某种方式将笔记从家里传递到档案和使用按钮删除部分。为此,我使用了 useContext 钩子,这样我就可以避免不必要的 prop 钻孔和复杂的代码。但不知何故它不起作用。谁能帮帮我?
import React, { createContext, useState } from "react";
export const dataContext = createContext([]);
const Context = ({ children }) => {
const [addData, setAddData] = useState([]); //to store all the values of the state data
const [archive, setArchive] = useState([]);
const [deleteNotes, setDeleteNotes] = useState([]);
return (
<>
<dataContext.Provider
value={{
addData,
setAddData,
archive,
setArchive,
deleteNotes,
setDeleteNotes,
}}
>
{children}
</dataContext.Provider>
</>
);
};
export default Context;
// export { dataContext };
import React, { useContext, useState } from "react";
import Inputbox from "../Components/Inputbox";
import { dataContext } from "../Components/Context";
import { v4 as uuid } from "uuid";
import SingleNote from "../Components/SingleNote";
const Notes = () => {
const [loading, setLoading] = useState(true);
const { addData, setAddData, setArchive, setDeleteNotes } =
useContext(dataContext);
//Math.random can also be used here but to make things simpler we have used a npm package as we don't know how many notes will a person will save
const [show, setShow] = useState(false); //to toggle between between the main note and the big note
const [data, setData] = useState({
//to stores all the values given by the user
id: uuid(),
title: "",
description: "",
});
const addNote = () => {
setAddData((oldData) => {
return [...oldData, data]; // Calling the done function using the addNote function
});
};
const Delete = (index) => {
const DelArray = addData.filter((Val) => {
return index !== Val.id;
});
setAddData(DelArray);
setDeleteNotes((preArr) => [addData, ...preArr]);
};
const Archive = (index) => {
const ArchiveArray = addData.filter((Val) => {
return index !== Val.id;
});
setAddData(ArchiveArray);
setArchive((preArr) => [addData, ...preArr]);
};
const handleClickAway = (e, val) => {
e.preventDefault();
setShow(false); //if data filed is blank, close the input fields
//if data field is not empty
if (data.title || data.description) {
setLoading(false);
addNote(val);
setData({
title: "",
description: "",
});
}
};
return (
<>
<Inputbox
handleClickAway={handleClickAway}
data={data}
setData={setData}
setAddData={setAddData}
show={show}
setShow={setShow}
/>
{loading ? (
<div style={{ marginLeft: "30%", marginTop: "5%" }}>
<div className="icon-1">
<i class="fa-regular fa-note-sticky"></i>
</div>
<div className="fs-3 fw-bold opacity-50">
Your Notes will Appear Here
</div>
</div>
) : (
<SingleNote addData={addData} Delete={Delete} Archive={Archive} />
)}
</>
);
};
export default Notes;
import React from "react";
const SingleNote = ({ addData, Delete, Archive }) => {
return (
<>
<div className="row mt-5 d-flex">
{addData &&
addData.map((Val, index) => {
const { title, description, id } = Val;
return (
<>
<div className="note m-3" key={index} id={index}>
<div className="fs-4 fw-bold">{title}</div>
<br />
<p>{description}</p>
<div className="d-flex flex-row-reverse">
<div
onClick={() => Delete(id)}
style={{ cursor: "pointer" }}
title="Delete"
>
<i className="fa-regular fa-trash-can fs-4 py-2 text-danger mx-3"></i>
</div>
<div
onClick={() => Archive(id)}
style={{ cursor: "pointer" }}
title="Archive"
>
<i className="fa-solid fa-boxes-stacked fs-4 py-2 text-success"></i>
</div>
</div>
</div>
</>
);
})}
</div>
</>
);
};
export default SingleNote;
import React, { useContext } from "react";
import { dataContext } from "../Components/Context";
const Archive = () => {
const { archive, setAddData, setArchive, setDeleteNotes } =
useContext(dataContext);
const Delete = (index) => {
const DelArray = archive[0].filter((Val) => {
return index !== Val.id;
});
setDeleteNotes(DelArray);
setAddData((preArr) => [archive, ...preArr]);
};
const UnArchive = (index) => {
const ArchiveArray = archive[0].filter((Val) => {
return Val.id !== index;
});
setArchive(ArchiveArray);
setAddData((preArr) => [...preArr, archive]);
};
return (
<>
<div className="row mt-5 d-flex">
{archive.map((Val, index) => {
const entry = Val[0];
const { title, description, id } = entry;
return (
<>
<div className="note m-3" key={index} id={index}>
<div className="fs-4 fw-bold">{title}</div>
<br />
<p>{description}</p>
<div className="d-flex flex-row-reverse">
<div
onClick={() => Delete(id)}
style={{ cursor: "pointer" }}
title="Delete"
>
<i className="fa-regular fa-trash-can fs-4 py-2 text-danger mx-3"></i>
</div>
<div
onClick={() => UnArchive(id)}
style={{ cursor: "pointer" }}
title="Unarchive"
>
<i className="fa-solid fa-arrow-up-from-ground-water fs-4 py-2 text-success"></i>
</div>
</div>
</div>
</>
);
})}
</div>
</>
);
};
export default Archive;
现在我面临的问题是我可以将数据从 notes 组件发送到 archive 组件,但它不会从 archive 组件返回到 notes 组件。请帮助我。
简而言之,用户面临的问题是他们试图在子组件中使用 useContext 挂钩,但上下文提供程序是在父组件中定义的。因此,子组件无法访问上下文值。
为了解决这个问题,上下文提供者需要放在组件树中更高的位置,以便所有需要访问上下文值的子组件都可以访问它们。
这里是一个如何在父组件中定义上下文提供者的例子:
import React, { createContext, useContext } from "react";
const MyContext = createContext();
function ParentComponent() {
return (
<MyContext.Provider value={"Hello"}>
<ChildComponent />
</MyContext.Provider>
);
}
function ChildComponent() {
const value = useContext(MyContext);
return <div>{value}</div>;
}
在此示例中,MyContext 是使用 createContext 函数定义的。在 ParentComponent 中,上下文提供者是使用 MyContext.Provider 组件定义的,其 value 属性设置为需要与子组件共享的值。
在 ChildComponent 中,useContext 钩子用于访问上下文值。
希望对您有所帮助!如果您还有其他问题,请告诉我。