N.B.我在这里得到了答案,但这不是这个线程的重复问题
我正在尝试从一个具有API的可重用函数中获取数据。这是我的代码
usaData.js在另一页中
const useData = () => {
const [data, setData] = useState([]);
const fetchData = async (url, query, variable) => {
const queryResult = await axios.post(url, {
query: query,
variables: variable,
});
setData(queryResult.data.data);
};
return {data, fetchData}
};
我正在从MainPage.js文件中检索数据
export const MainPage = props => {
const [state, setState] = useState({
pharam: 'Yes',
value: '',
});
const [field, setField] = useState([])
const {data, fetchData} = useData()
const onClick = (event) => {
setState({ ...state, pharam: '', value: event });
fetchData(url, query, event)
setField(data)
}
return (
<div>
...
<Select
placeholder='select'
>
{field.map(item => (
<Select.Option key={item.name}>
{item.name}
</Select.Option>
))}
</Select>
<Button onClick={onClick}>Change Select</Button>
...
</div>
)
}
问题是onClick
函数中的setField(data)
没有立即更新,因为它是一个异步调用。因此,我尝试使用一个函数作为第二个参数
...
setField(data, () => {
console.log(data)
})
...
它以红色返回以下警告,但行为与之前类似,没有立即更新数据。
警告:来自useState((和useReducer((挂钩的状态更新不支持第二个回调参数。要在渲染后执行副作用,请使用useEffect((在组件主体中声明它。
根据警告,我尝试在onClick
函数中使用useEffect()
...
const onClick = (event) => {
setState({ ...state, pharam: '', value: event });
useEffect(() => {
fetchData(url, query, event)
setField(data)
}, [data])
}
...
返回错误
React Hook"useEffect";在函数"中被调用;onClick"既不是React函数组件,也不是自定义React Hook函数。React组件名称必须以大写字母开头。React Hook名称必须以单词"开头;使用";
我必须在哪里进行更改?由于setField
将立即更新field
,我如何获得预期行为?
我的建议是不要在自定义挂钩中设置State,而不是返回promise。
usaData.js
const useData = () => {
const fetchData = async (url, query, variable) => {
return await axios.post(url, {
query: query,
variables: variable,
});
};
return { fetchData };
};
在MainPage.js中
现在,当您触发onClick函数时,只需使用wait或then语法调用fetchData函数,在成功调用api后,您将在newData变量中返回结果,您可以使用它来更新状态。
注意:这将为您节省额外的useEffect。
export const MainPage = (props) => {
const [state, setState] = useState({
pharam: "Yes",
value: "",
});
const [field, setField] = useState([]);
const { fetchData } = useData();
const onClick = async (event) => {
setState({ ...state, pharam: "", value: event });
let newData = await fetchData(url, query, event);
console.log("===>", newData.data.data);
setField(newData.data.data);
};
return (
<div>
...
<Select placeholder="select">
{field.map((item) => (
<Select.Option key={item.name}>{item.name}</Select.Option>
))}
</Select>
<Button onClick={onClick}>Change Select</Button>
...
</div>
);
};
您的案例中的问题是setField
在获取数据之前得到调用。
因此,您可以有一个useEffect
,每次更改data
时都会执行它。
useEffect(() => {
if(data.length > 0) {
setField(data);
}
}, [data])
const onClick = (event) => {
setState(prev => ({ ...prev, pharam: '', value: event }));
fetchData(url, query, event);
}
据我所知,React异步设置其状态。因此,为了更新状态字段,您需要一个useEffect钩子。您的useEffect方法是正确的,只是它需要放置在Click外部(直接在组件函数中(。
export const MainPage = () => {
...
useEffect(() => {
setField(data)
},[data])
...
}