如何停止useDispatch()无限调度动作?

时间:2019-11-06 21:30:41

标签: react-redux react-hooks

背景

我正在使用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结合使用并且不依赖于类组件的解决方案。

3 个答案:

答案 0 :(得分:0)

在父组件上


 const dispatch = useDispatch();
 useEffect(()=> dispatch(actions.fetchCollectionData(), []);

应该工作。 由于某些原因,当您尝试使用useEffect时,它似乎没有分派

答案 1 :(得分:0)

已更改:

const dispatch = useDispatch(); useEffect(()=> dispatch(actions.fetchCollectionData(), []);

收件人:

const dispatch = useDispatch(); useEffect(()=> {dispatch(actions.fetchCollectionData()}, []);

答案 2 :(得分:0)

对于你们中的那些人,上面的方法并没有解决它,useEffect中的一个简单的if语句可以解决它。就我而言,我的值最初为null,因此我想模仿旧的ComponentDidMount方法。这是简单明了的解决方案。

  useEffect(() => {
        if (yourvalue === null) 
           dispatch(actiontodispatch()); 
        }, []);

关键部分是开头为null / false或其他任何值的值。不过,不确定性能。