在打字稿中将 useState 作为道具传递
Passing useState as props in typescript
假设我有一个包含两个子组件的父组件:
const Parent = () => {
const [myVar, setmyVar] = useState(false)
return (
<>
<MyChildComponent1 myVar={myVar} setMyVar={setMyVar} \>
<MyChildComponent2 myVar={myVar} \>
</>
)
}
现在我该如何在 MyChildComponent2
中正确设置类型?
这是我到目前为止的想法:
const MyChildComponent1 = (
{myVar, setMyVar}:
{myVar: boolean, setMyVar: (value: boolean) => void}) = (...)
setMyvar
的类型是否正确?还是应该是其他东西?
与函数 return 调用 useState
匹配的类型将是:
setMyVar: (value: boolean | ((prevVar: boolean) => boolean)) => void;
如果我们查看 DefinitelyTyped
[1] 中的类型定义文件,我们可以看到 return 类型中的第二个类型是调度:
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
因此提供的通用类型被传递给 SetStateAction<S>
,其定义为:
type SetStateAction<S> = S | ((prevState: S) => S);
所以基本上,您的组件的接口如下:
interface IProps {
myVar: boolean;
setMyVar?: (value: boolean | (prevVar: boolean) => boolean) => void;
}
正如@Retsam 所说,最好使用 React 的导出类型:
import { Dispatch, SetStateAction } from "react";
interface IProps {
myVar: boolean;
setMyVar?: Dispatch<SetStateAction<boolean>>;
}
参考资料:
[1] https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L845
调度和 SetStateAction 类型
如@Retsam 所述,您还可以从 React 导入和使用类型 Dispatch
和 SetStateAction
:
import React, { Dispatch, SetStateAction } from 'react';
const MyChildComponent1 = (
myVar: boolean,
setMyVar: Dispatch<SetStateAction<boolean>>
) => {...};
奖金
当我发现自己经常使用它时,我创建了一个类型别名来帮助提高可读性
import React, { Dispatch, SetStateAction } from 'react';
type Dispatcher<S> = Dispatch<SetStateAction<S>>;
const MyChildComponent1 = (
myVar: boolean,
setMyVar: Dispatcher<boolean>,
) => {...};
希望这对您有所帮助。
添加到@fiz 的评论中,他的块代码对我来说有点不起作用:
import React, { Dispatch, SetStateAction } from 'react';
const MyChildComponent1 = (
myVar: boolean,
setMyVar: Dispatch<SetStateAction<<boolean>>
) => {...};
我不得不设置 setMyVar: Dispatch<SetStateAction<boolean>>
(括号太多)
也可以使用 Interface 和 React 组件来完成。
MainComponent.tsx
Value assignment of the useState component defined in Main is done in
the child component. When this field is triggered, the code in useEffect will run.
import React, { useEffect } from 'react';
import Login from './views/Login/index';
const App: React.FunctionComponent = () => {
const [isAuthenticated, setAuthenticatedStatus] = React.useState(false);
useEffect(() => {
if (isAuthenticated)
window.location.href = "<redirect url>";
}, [isAuthenticated]);
return (<Login setLoginStatus={setAuthenticatedStatus} />)
};
export default App;
ChildComponent.tsx
import { Dispatch, SetStateAction, FunctionComponent } from 'react';
import authService from '../../apiServices/authService';
interface IProps {
setLoginStatus: Dispatch<SetStateAction<boolean>>;
}
const Login: FunctionComponent<IProps> = (props: IProps) => {
const login = async (username: string, password: string) => {
const response = await authService.authenticateUser(username, password);
if (response && response.statusCode == 200 && response.result.accessToken) {
props.setLoginStatus(true);
}
else {
// ...
}
};
return (
<>
...
</>
);
};
export default Login;
假设我有一个包含两个子组件的父组件:
const Parent = () => {
const [myVar, setmyVar] = useState(false)
return (
<>
<MyChildComponent1 myVar={myVar} setMyVar={setMyVar} \>
<MyChildComponent2 myVar={myVar} \>
</>
)
}
现在我该如何在 MyChildComponent2
中正确设置类型?
这是我到目前为止的想法:
const MyChildComponent1 = (
{myVar, setMyVar}:
{myVar: boolean, setMyVar: (value: boolean) => void}) = (...)
setMyvar
的类型是否正确?还是应该是其他东西?
与函数 return 调用 useState
匹配的类型将是:
setMyVar: (value: boolean | ((prevVar: boolean) => boolean)) => void;
如果我们查看 DefinitelyTyped
[1] 中的类型定义文件,我们可以看到 return 类型中的第二个类型是调度:
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
因此提供的通用类型被传递给 SetStateAction<S>
,其定义为:
type SetStateAction<S> = S | ((prevState: S) => S);
所以基本上,您的组件的接口如下:
interface IProps {
myVar: boolean;
setMyVar?: (value: boolean | (prevVar: boolean) => boolean) => void;
}
正如@Retsam 所说,最好使用 React 的导出类型:
import { Dispatch, SetStateAction } from "react";
interface IProps {
myVar: boolean;
setMyVar?: Dispatch<SetStateAction<boolean>>;
}
参考资料: [1] https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L845
调度和 SetStateAction 类型
如@Retsam 所述,您还可以从 React 导入和使用类型 Dispatch
和 SetStateAction
:
import React, { Dispatch, SetStateAction } from 'react';
const MyChildComponent1 = (
myVar: boolean,
setMyVar: Dispatch<SetStateAction<boolean>>
) => {...};
奖金
当我发现自己经常使用它时,我创建了一个类型别名来帮助提高可读性
import React, { Dispatch, SetStateAction } from 'react';
type Dispatcher<S> = Dispatch<SetStateAction<S>>;
const MyChildComponent1 = (
myVar: boolean,
setMyVar: Dispatcher<boolean>,
) => {...};
希望这对您有所帮助。
添加到@fiz 的评论中,他的块代码对我来说有点不起作用:
import React, { Dispatch, SetStateAction } from 'react';
const MyChildComponent1 = (
myVar: boolean,
setMyVar: Dispatch<SetStateAction<<boolean>>
) => {...};
我不得不设置 setMyVar: Dispatch<SetStateAction<boolean>>
(括号太多)
也可以使用 Interface 和 React 组件来完成。
MainComponent.tsx
Value assignment of the useState component defined in Main is done in the child component. When this field is triggered, the code in useEffect will run.
import React, { useEffect } from 'react';
import Login from './views/Login/index';
const App: React.FunctionComponent = () => {
const [isAuthenticated, setAuthenticatedStatus] = React.useState(false);
useEffect(() => {
if (isAuthenticated)
window.location.href = "<redirect url>";
}, [isAuthenticated]);
return (<Login setLoginStatus={setAuthenticatedStatus} />)
};
export default App;
ChildComponent.tsx
import { Dispatch, SetStateAction, FunctionComponent } from 'react';
import authService from '../../apiServices/authService';
interface IProps {
setLoginStatus: Dispatch<SetStateAction<boolean>>;
}
const Login: FunctionComponent<IProps> = (props: IProps) => {
const login = async (username: string, password: string) => {
const response = await authService.authenticateUser(username, password);
if (response && response.statusCode == 200 && response.result.accessToken) {
props.setLoginStatus(true);
}
else {
// ...
}
};
return (
<>
...
</>
);
};
export default Login;