Reputation: 93
I am trying useref with react-hooks but when i call the setAccountVal method , although the state of child changes when i alert the value it is still "Ege". Do you have any idea about this case ?
import React, { useState, useRef, useImperativeHandle, useEffect, forwardRef } from "react";
interface A {
name?: string;
}
const Child = forwardRef((props: A, ref) => {
const [acc, setAcc] = useState("Ege");
useImperativeHandle(ref, () => ({
getAlert(value: string) {
alert("getAlert from Child===>" + value);
},
setAccountVal(val: string) {
setAcc(val);
},
acc
}));
useEffect(
() => {
debugger;
setAcc(props.name || "dummy");
console.log(acc + " --");
},
[props.name]
);
const changeState = (e:React.FormEvent<HTMLInputElement>)=>{
setAcc(e.currentTarget.value);
}
return <input onChange={changeState}></input>;
})
function App() {
let [name, setName] = useState("Nate");
let nameRef = useRef<any>(null);
const submitButton = () => {
debugger;
const comp = nameRef.current;
comp.setAccountVal("Mahmut");
comp.getAlert(comp.acc);
};
return (
<div className="App">
<p>{name}</p>
<div>
<button type="button" onClick={submitButton}>
Submit
</button>
<Child ref={nameRef} />
</div>
</div>
);
}
export default App;
When i call a normal method , i can see what i want. But the problem is that i can see new state value on acc state but when i take it from parent it is displaying the old ( actually the initial state val ("Ege")) state value.
Edit : Actually what i want to do is below
//Child component with forwardRef
const [account, setAccount] = useState("defaultAccount");
const [branch, setBranch] = useState("defaultBranch");
const [person, setPerson] = useState("defaultPerson");
useImperativeHandle(ref, () => ({
selectedAccount: account,
selectedBranch: branch,
selectedPerson: person
}));
//Parent component
const childComponentRef = useRef(null);
//Is it possible to change child component's state? Is it allowed?
childComponentRef.current.selectedAccount = "new account";
childComponentRef.current.selectedBranch = "new branch";
childComponentRef.current.selectedPerson = "new person";
alert(childComponentRef.current.selectedAccount);
alert(childComponentRef.current.selectedBranch);
alert(childComponentRef.current.selectedPerson);
//We can change these variables but child component does not rerender with new values.
Ok! I've found the solution. When i use the ref variables with getter setter now i can set also get the current values with useRef!!
//Child component with forwardRef
const [account, setAccount] = useState("defaultAccount");
const [branch, setBranch] = useState("defaultBranch");
const [person, setPerson] = useState("defaultPerson");
useImperativeHandle(ref, () => ({
**get account(){
return account;
},
set account(val : string){
setAccount(val);
},**
selectedBranch: branch,
selectedPerson: person
}));
//Parent component
const childComponentRef = useRef(null);
//Is it possible to change child component's state? Is it allowed?
childComponentRef.current.selectedAccount = "new account";
childComponentRef.current.selectedBranch = "new branch";
childComponentRef.current.selectedPerson = "new person";
alert(childComponentRef.current.selectedAccount);
alert(childComponentRef.current.selectedBranch);
alert(childComponentRef.current.selectedPerson);
//We can change these variables but child component does not rerender with new values
Detailed Demo :
Upvotes: 2
Views: 8525
Reputation: 475
It is because you're using useImperativeHandle without setting any inputs to it, so the functions never get updated. Just add acc as an input, and it will work:
useImperativeHandle(ref, () => ({
getAlert(value: string) {
alert("getAlert from Child===>" + value);
},
setAccountVal(val: string) {
setAcc(val);
},
acc
}), [acc]);
Upvotes: 4