reactjs - 传递给组件的 setState 应该设置什么 Typescript 类型
我有一些父组件,比如:
const ParentOne = () => {
const [error, setError] = useState<{ one: boolean }>({ one: false });
...omit
return (
<>
<Child setErr={setError} name={"one"} />
</>
);
};
const ParentTwo = () => {
const [error, setError] = useState<{ one: boolean; two: boolean }>({
one: false,
two: false,
});
...omit
return (
<>
<Child setErr={setError} name={"one"} />
<Child setErr={setError} name={"two"} />
</>
);
};
以及具有不同数量的子组件和不同
const[...] = useState<{ one: boolean; two: boolean; ...n: boolean }>({
one: false,
two: false,
...,
n: false
});
这是我的子组件:
const Child: FC<IChild> = ({ setErr, name }) => {
const handleClick = () => {
setErr((prev) => ({ ...prev, [name]: true }));
};
return <button onClick={handleClick}/>;
};
我不知道应该为 setErr 设置哪种类型,因为 useState 对不同的父组件有不同的泛型。我尝试了这样做:
interface IChild {
setErr: React.Dispatch<React.SetStateAction<{ [key: string]: boolean }>>;
name: string;
}
但在每个父组件中,setErr 需要 IChild 中类型与 useState 中泛型完全匹配
答案#1
你所写的带有 Child 的 setErr 属性的真实类型是:
type ErrorSetter = React.Dispatch<React.SetStateAction<{[key: string]: boolean}>>;
我看到两个选择:
按原样使用
Child,并对setError使用类型断言(有几种方法,下面会详细说明)。使用自定义钩子并简化
Child
我的偏好是#2,但让我们看看它们每一个:
使用 Child 并按类型断言书写
所以如果我们使用那个错误设置器,我们有:
type ErrorSetter = React.Dispatch<React.SetStateAction<{[key: string]: boolean}>>;
interface IChild {
setErr: ErrorSetter;
name: string;
}
如何在不经常写as的情况下使用它?
总体来说,我们不会这样做,但你可能只对每个父组件做一次:
const ParentTwo = () => {
const [error, setError] = useState({
one: false,
two: false,
});
const setErr = setError as ErrorSetter;
//
return (
<>
<Child setErr={setErr} name="one" />
<Child setErr={setErr} name="two" />
</>
);
};
这相当方便,并且保持了 Child 不变,尽管正如类型断言常常(总是?)的情况一样,它并不是完全类型安全的。
使用自定义钩子
但我倾向于使用自定义钩子并简化 Child。这个钩子是:
const useErrorState = <T,>(initial: T): [T, (name: keyof T) => void] => {
const [error, realSetError] = useState(initial);
const setError = useCallback(
(name: keyof T) => {
realSetError(prev => ({...prev, [name]: true}));
},
[]
);
return [error, setError];
};
如果你不需要 setErr 保持稳定,那么你可以这样使用它:
const ParentTwo = () => {
const [error, setError] = useErrorState({
one: false,
two: false,
});
//
return (
<>
<Child setErr={() => setError("one")} />
<Child setErr={() => setError("two")} />
</>
);
};
游乐场链接
...或者如果你这样做是为了避免 Child 重新渲染(这假设 Child 使用了 React.memo 或者 [在类组件中] PureComponent 或 shouldComponentUpdate):
const ParentTwo = () => {
const [error, setError] = useErrorState({
one: false,
two: false,
});
const setErrorOne = useCallback(() => setError("one"), []);
const setErrorTwo = useCallback(() => setError("two"), []);
//
return (
<>
<Child setErr={setErrorOne} />
<Child setErr={setErrorTwo} />
</>
);
};
游乐场链接
