Reputation: 58893
Given the following simple components:
function ValueInput (props) {
const [val, setVal] = useState(props.value);
return <input value={val} onChange={v => setVal(v)}/>;
}
function MyComponent (props) {
const [val, setVal] = useState(props.value);
return (
<div>
<div>{val}</div>
<ValueInput value={val}/>
</div>
);
}
I'm mounting them in order to test them with Enzyme and Jest:
const component = mount(<MyComponent value={42}/>);
const inputEl = component.find('input');
How do I simulate changing the value of the inner input and have it reflected in the div? I'm trying with the following code, but it doesn't work:
console.log(component.debug());
inputEl.simulate('change', { target: { value: 24 } });
// component.update();
console.log(component.debug());
Even forcing the update doesn't change the values. The printed component stays the same:
<MyComponent value={42}>
<div>
<div>
42
</div>
<ValueInput value={42}>
<input value={42} onChange={[Function: onChange]} />
</ValueInput>
</div>
</MyComponent>
Upvotes: 1
Views: 525
Reputation: 10873
In your code
function ValueInput (props) {
const [val, setVal] = useState(props.value);
return <input value={val} onChange={v => setVal(v)}/>;
}
You're only changing the value of the child component, the value of the parent is not affected, since you didn't call the parent's setVal
method.
You need to update your code:
function ValueInput (props) {
const [val, setVal] = useState(props.value);
const handleChange = e => {
const {value} = e.target;
setVal(value);
props.setParentVal(value) // Pass the changed value to the parent
}
return <input value={val} onChange={handleChange}/>;
}
function MyComponent (props) {
const [val, setVal] = useState(props.value);
return (
<div>
<div>{val}</div>
<ValueInput value={val} setParentVal={setVal}/>
</div>
);
}
Also looking at the code, it is not necessary to duplicate the state inside your child component, you can use the parent's methods directly to manipulate and store input value:
function ValueInput ({val, setVal}) {
return <input value={val} onChange={setVal}/>;
}
function MyComponent (props) {
const [val, setVal] = useState(props.value);
const handleChange = e => {
const {value} = e.target;
setVal(value);
}
return (
<div>
<div>{val}</div>
<ValueInput value={val} setVal={handleChange}/>
</div>
);
}
Upvotes: 2