我需要使用ref
来获取孙子组件的状态,并通过使用useImperativeHandle
自定义它,简化了整个代码
here。
function App() {
const ref = useRef(null);
return (
<div className="App">
<button
onClick={() => console.log(ref.current.name, ref.current.age)}
>click me</button>
<FilterFather ref={ref} />
</div>
);
}
const FilterFather = (_, ref) => {
const filter1Ref = useRef(null);
const filter2Ref = useRef(null);
useImperativeHandle(ref, () => ({
name: filter1Ref.current.name,
age: filter2Ref.current.age,
}))
return (
<>
<Filter1 ref={filter1Ref}/>
<Filter2 ref={filter2Ref} />
</>
)
}
export default forwardRef(FilterFather);
const Filter1 = (props, ref) => {
const [name, setName] = useState('lewis')
useImperativeHandle(ref, () => ({
name
}), [name])
return (
<>
<div>
name:
<input
value={name}
onChange={e => setName(e.target.value)}
/>
</div>
</>
)
}
const Filter2 = (props, ref) => {
const [age, setAge] = useState(18)
useImperativeHandle(ref, () => ({
age
}), [age])
return (
<>
<div>
age:
<input
value={age}
onChange={e => setAge(e.target.value)}
/>
</div>
</>
)
}
export default {
Filter1: forwardRef(Filter1),
Filter2: forwardRef(Filter2),
}
forwardRef
和useImperativeHandle
的一层工作正常,两层出错了
答案 0 :(得分:1)
您不需要FilterFather
中的命令句柄。它不会向句柄添加/删除任何内容。您可以直接转发它:
const FilterFather = (_, ref) => {
return <Filter ref={ref} />;
};
还有一个问题,因为它不会正确更新。
useImperativeHandle(ref, () => ({
name: filterRef.current.name,
age: filterRef.current.age,
}), [filterRef]) // this will not update correctly
您通过了filterRef
作为依赖项,但是filterRef
是静态的,即使filterRef.current.name
或filterRef.current.age
发生更改也不会更改。
请注意,useImperativeHandle
不应用于从子组件中读取状态。实际上,不鼓励在反应中使用任何命令式方法,除非没有其他方法。在大多数情况下,如果您使用本质上必不可少的第三方库,就属于这种情况。
编辑:
给出更新后的代码,可以做到的是提高状态。它不需要任何参考:
export default function App() {
const [values, setValues] = useState({
name: "lewis",
age: 18
});
const handleChange = useCallback(
(key, value) => setValues(current => ({ ...current, [key]: value })),
[]
);
return (
<div className="App">
<button onClick={() => console.log(values.name, values.age)}>
click me
</button>
<FilterFather values={values} onChange={handleChange} />
</div>
);
}
const FilterFather = props => {
return (
<>
<Filter label="Name" name="name" {...props} />
<Filter label="Age" name="age" {...props} />
</>
);
};
const Filter = ({ label, name, values, onChange }) => {
const handleChange = useCallback(e => onChange(name, e.target.value), [
name,
onChange
]);
return (
<>
<div>
<label>{label}:</label>
<input value={values[name]} onChange={handleChange} />
</div>
</>
);
};