背景
我正在使用React-Redux和React Hooks进行项目。
我有一个组件,该组件调度一个动作fetchCollectionData()
,该组件首先调度一个动作requestCollectionData()
,该动作将reducer的waiting属性更新为true。然后fetchCollectionData()
发出超级代理请求,以从服务器获取数据。响应返回后,fetchCollectionData()
调度另一个动作receiveCollectionData()
,该动作将使用结果更新reducer并将waiting属性设置为false。 API结果将带回的数据向下传递到子组件中的表。
问题:useDispatch()无限循环地调度fetchCollectionData()
操作。我只希望在组件安装时将此动作调度一次。
尝试:我曾尝试使用useEffect()钩子useEffect(fetchCollectionData(),[])
,但收到一条错误消息,指出useEffect不应用于承诺。
错误文本:
Warning: An effect function must not return anything besides a function,which is used for clean-up.
It looks like you wrote useEffect(async () => ...) or returned a Promise. Instead,write the async function inside your effect and call it immediately:
useEffect(() => {
async function fetchData() {
// You can await here
const response = await MyAPI.getData(someId);
// ...
}
fetchData();
},[someId]); // Or [] if effect doesn't need props or state
in ContainerComponent (created by Context.Consumer)
in Route (at App.js:35)
in Switch (at App.js:33)
in div (at App.js:20)
in Router (created by BrowserRouter)
in BrowserRouter (at App.js:19)
in App (at Root.js:8)
in Provider (at Root.js:7)
in Root (at src/index.js:8)
我尝试将操作更改为export async function fetchCollectionData()
,但这导致我遇到更多错误。
父组件
export const ContainerComponent = () => {
const dispatch = useDispatch();
dispatch(actions.fetchCollectionData());
const data = useSelector(state => state.accountMaintenanceReducer.result);
const rows = data ? data : [];
return (
<div style={containerStyle}>
<div classname="section-header">
<span>account Maintenance</span>
</div>
<TableComponent rows={rows} />
</div>
);
};
子组件
import React from "react";
import { Table,TableHead,TableBody,TableRow,TableCell } from '@material-ui/core';
const columns = [,{name: 'Primary Owner',key: 'owner'},{name: 'Mailing Address',key: 'address'},];
const dataToRows = (data) => {
if (data.rows.length) {
return data.rows.map(row => {
const index = row.ownerAndAddress.indexOf(String.fromCharCode(13));
const owner = row.ownerAndAddress.substring(0,index);
const address = row.ownerAndAddress.substring(index + 2);
return {
owner: owner,address: address,}
});
}
};
export const TableComponent = (data) => {
const rows = dataToRows(data);
return (
<Table>
<TableHead>
<TableRow>
{columns.map(column => (
<TableCell key={columns.indexOf(column)}>
{column.name}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{ rows ?
rows.map(row => (
<TableRow key={rows.indexOf(row)}>
{ Object.keys(row).map(cell => (
<TableCell classname={cell} key={cell}>
{row[cell]}
</TableCell>
))}
</TableRow>
)) :
<TableRow>
<TableCell>No Data</TableCell>
</TableRow>
}
</TableBody>
</Table>
);
};
动作
export function receiveCollectionData(body) {
return {
type: 'RECEIVE_COLLECTION_DATA',result: body,}
}
export function requestCollectionData() {
return {
type: 'REQUEST_COLLECTION_DATA',}
}
export function fetchCollectionData() {
return dispatch => {
dispatch(requestCollectionData());
return request.get(`api/accounts/getcollectionBySearch?searchString=Smith`)
.then(res => res.body)
.then(body=> dispatch(receiveCollectionData(body)))
}
}
减速器
export default (state = {},action) => {
switch (action.type) {
case 'GET_COLLECTION_DATA':
return {
...state,waiting: true
};
case 'RECEIVE_COLLECTION_DATA':
return {
...state,result: action.result,waiting: false
};
default:
return state;
}
}
所需的解决方案:
我想做的是模仿componentDidmount()
的功能,并在组件安装后分派fetchCollectionData()
。似乎fetchCollectionData()
一旦解决,就会再次调度,从而导致无限循环。
免责声明:
目标是获得一种将React Hooks与Redux结合使用并且不依赖于类组件的解决方案。