在TypeScript中如何在React Context中初始化并传递函数?
解决TypeScript中createContext初始化异步函数getResults的问题
问题场景
在TypeScript项目中使用createContext时,定义了包含异步函数getResults的ContextParametersType接口,但不知道如何在创建Context时初始化该函数,同时Provider组件未将getResults传入Context的value中。
相关代码如下:
接口定义
interface ContextParametersType { greenValue: { greenStatus: Set<EnumType>, setGreenStatus: Dispatch<SetStateAction<Set<EnumType>>> }; redValue: { redStatus: Set<EnumType>, setRedStatus: Dispatch<SetStateAction<Set<EnumType>>> }; searchValue: { searchTerm: string, setSearchTerm: Dispatch<SetStateAction<string>> } getResults: () => void }
未完成的Context初始化
const StateContext = createContext<ContextParametersType>({ greenValue: { greenStatus: new Set<EnumType>(), setGreenStatus: () => {} }, redValue: { redStatus: new Set<EnumType>(), setRedStatus: () => {} }, searchValue: { searchTerm: '', setSearchTerm: () => {} }, // 此处不知如何初始化getResults })
Provider组件
export const StateContextProvider = ({ children }: Props) => { const [results, setResults] = useState<Array<EnumType>>(); const [greenStatus, setGreenStatus] = useState(new Set<EnumType>()); const [redStatus, setRedStatus] = useState(new Set<EnumType>()); const [searchTerm, setSearchTerm] = useState<string>('') const greenValue = { greenStatus, setGreenStatus }; const redValue = { redStatus, setRedStatus }; const searchValue = { searchTerm, setSearchTerm }; const getResults = async () => { const axios = require("axios"); const options = { method: 'GET', url: 'https://google-search72.p.rapidapi.com/search', params: {query: 'rapidapi', gl: 'us', lr: 'en', num: '10', start: '1'}, headers: { 'X-RapidAPI-Key': 'SIGN-UP-FOR-KEY', 'X-RapidAPI-Host': 'google-search72.p.rapidapi.com' } }; axios.request(options).then(function (response: { data: any; }) { console.log(response.data); }).catch(function (error: any) { console.error(error); }); }; return ( <StateContext.Provider value={{ greenValue, redValue, searchValue }}> {children} </StateContext.Provider> ); };
解决方案
1. 初始化Context时的getResults占位
ContextParametersType中getResults的类型为() => void,异步函数虽然返回Promise,但TypeScript允许将其赋值给() => void类型(void不关心返回值)。直接给一个空的异步函数作为默认值即可:
const StateContext = createContext<ContextParametersType>({ greenValue: { greenStatus: new Set<EnumType>(), setGreenStatus: () => {} }, redValue: { redStatus: new Set<EnumType>(), setRedStatus: () => {} }, searchValue: { searchTerm: '', setSearchTerm: () => {} }, // 初始化空的异步函数占位 getResults: async () => {} })
如果倾向严格匹配同步函数类型,也可以使用普通空函数:
getResults: () => {}
2. 完善Provider的value传递
必须将Provider中定义的getResults加入到Context的value中,否则消费Context时无法获取到真正的实现:
修改Provider的return部分:
return ( <StateContext.Provider value={{ greenValue, redValue, searchValue, getResults }}> {children} </StateContext.Provider> );
完整修正后的代码
修正后的Context初始化
const StateContext = createContext<ContextParametersType>({ greenValue: { greenStatus: new Set<EnumType>(), setGreenStatus: () => {} }, redValue: { redStatus: new Set<EnumType>(), setRedStatus: () => {} }, searchValue: { searchTerm: '', setSearchTerm: () => {} }, getResults: async () => {} })
修正后的Provider组件
export const StateContextProvider = ({ children }: Props) => { const [results, setResults] = useState<Array<EnumType>>(); const [greenStatus, setGreenStatus] = useState(new Set<EnumType>()); const [redStatus, setRedStatus] = useState(new Set<EnumType>()); const [searchTerm, setSearchTerm] = useState<string>('') const greenValue = { greenStatus, setGreenStatus }; const redValue = { redStatus, setRedStatus }; const searchValue = { searchTerm, setSearchTerm }; const getResults = async () => { import axios from 'axios'; const options = { method: 'GET', url: 'https://google-search72.p.rapidapi.com/search', params: {query: 'rapidapi', gl: 'us', lr: 'en', num: '10', start: '1'}, headers: { 'X-RapidAPI-Key': 'SIGN-UP-FOR-KEY', 'X-RapidAPI-Host': 'google-search72.p.rapidapi.com' } }; try { const response = await axios.request(options); console.log(response.data); // 可在此处更新results状态 // setResults(response.data); } catch (error) { console.error(error); } }; return ( <StateContext.Provider value={{ greenValue, redValue, searchValue, getResults }}> {children} </StateContext.Provider> ); };
额外建议:将axios的require改为顶部import,并把.then/.catch改为async/await语法,更符合TypeScript代码风格。
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

