I'm trying to change the state of a parent component from a child component. My Component structure is basically like this.
<Admin>
<Nav/> //Nav Bar
{changePass && props.children} //Change Password Form
</Admin>
My Nav, in turn has several child components:
<NavBar>
<NavItem menu="☰">
<DropdownMenu/>
</NavItem>
</NavBar>
In the DropdownMenu component there are child button Components, Logout, Delete Account, and Change Password. The latter is from which I want to toggle the Change Password Component in Admin.tsx. In DropdownItem.tsx I have a bit of code to detect the button click:
//ChangePassContext.tsx
import { createContext } from "react";
export let ChangePassContext = createContext<boolean>(false)
//DropdownItem.tsx
import { ChangePassContext } from "../Context/ChangePasswordContext/ChangePassContext";
let changePass = useContext(ChangePassContext)
//When window loads, get previous state from local storage
if (destination === CHANGEPSSWD){
if (localStorage.getItem('changePass') === "true"){
changePass = !changePass
}
}
const handleMenu = (event: MouseEvent) => {
event.preventDefault();
if (destination === CHANGEPSSWD) {
// Open Change Password Form
if (changePass === false){
localStorage.setItem('changePass', "true")
} else {
localStorage.removeItem('changePass')
}
changePass = !changePass
console.log(changePass)
window.location.reload() //I'll reference this in a moment
}
}
I then call changePass in my Admin.tsx file and update it using what I have stored in my local storage:
let changePass = useContext(ChangePassContext)
if (localStorage.getItem("changePass") === "true"){
changePass = !changePass
}
And as shown above, the changePass context controls whether the ChangePassword Form is opened or closed:
{changePass && props.children} //Change Password Form
The only problem is I can't get the state to update from my DropdownItem component to my Admin parent component. The only way I can get it to update is if I reload the page, as I do in the DropdownItem component, resulting in a very poor user Experience:
Ironically, as you can see, I have a working menu component (passing down props to children seems easier), and I did it with the useContext provider and useState. The problem is that when I try to set the context with useState, the context won't update, and I don't know why. Originally I tried setting my DropdownItem function to something simple like this:
if (destination === CHANGEPSSWD) {
// Open Change Password Form
setChangePass(!changePass)
}
I also don't want to use localStorage at all but I can't seem to get useContext to work without it.
I'm very frustrated, especially with how ugly this code is. I hope someone can help.
CodePudding user response:
Make your Admin file like this:
//Admin.tsx
import { createContext } from "react";
export const ChangePassContext = createContext();
function App() {
const[changePass, setChangePass] = useState({});
return (
<ChangePassContext.Provider value={[changePass, setChangePass]}>
<Admin>
<Nav/> //Nav Bar
{changePass && props.children} //Change Password Form
</Admin>
</UserContext.Provider>
);
}
export default App;
Then you can use it in your DropdownItem.tsx
//DropdownItem.tsx
import { useContext } from 'react';
import { ChangePassContext } from '../../App';
const DropdownItem = () => {
const[changePass, setChangePass]= useContext(ChangePassContext);
if (destination === CHANGEPSSWD) {
// Open Change Password Form
setChangePass(!changePass)
}
return (
//your code
);
};