如何在功能性 React JS 组件中获取数据?

Posted

技术标签:

【中文标题】如何在功能性 React JS 组件中获取数据?【英文标题】:How to fetch data in a functional react JS component? 【发布时间】:2020-08-04 22:27:34 【问题描述】:

我正在开发一个 React JS、Redux、GraphQL、TypeScript 应用程序。

我想知道如何调用从我的容器中通过 GraphQL 获取数据和更新状态的函数。

通过 GraphQL 加载数据的动作名称为 appActions.getAppData();

但它会导致无限刷新循环,因为它会触发 (StatusActions.startAppLoading());这也会更新状态。

我想知道如何解决此问题或如何将 /Main/index.tsx 重写为类组件并从 componentDidMount() 调用 startAppLoading()。

提前谢谢你。

ma​​in.tsx

import React from 'react';
import ReactDOM from 'react-dom';
import  Provider  from 'react-redux';
import  createBrowserHistory  from 'history';
import  configureStore  from 'app/store';
import  Router  from 'react-router';
import  App  from './app';

// prepare store
const history = createBrowserHistory();
const store = configureStore();

ReactDOM.render(
  <Provider store=store>
    <Router history=history>
      <App />
    </Router>
  </Provider>,
  document.getElementById('root')
);

app/index.tsx

import React from 'react';
import  Route, Switch, Redirect  from 'react-router-dom';
import  App as Main  from 'app/containers/Main';
import  hot  from 'react-hot-loader';

let currentContainer = Main;

export const App = hot(module)(() => (
  <Switch>
    <Route exact path="/" component=currentContainer />
    <Route path="*">
      <Redirect to="https://google.com" />
    </Route>
  </Switch>
));

app/containers/Main/index.tsx

import React from 'react';
import style from './style.css';
import  RouteComponentProps  from 'react-router';
import  useDispatch, useSelector  from 'react-redux';
import  useTodoActions  from 'app/actions';
import  useAppActions  from 'app/actions';
import  RootState  from 'app/reducers';
import  Header, TodoList, Footer  from 'app/components';

export namespace App 
  export interface Props extends RouteComponentProps<void> 


export const App = ( history, location : App.Props) => 
  const dispatch = useDispatch();
  const appActions = useAppActions(dispatch);

const  apps  = useSelector((state: RootState) => 
    return 
      apps: state.apps
    ;
  );
  appActions.getAppData();

  return (
    <div className=style.normal>
      <Header />
      <TodoList appActions=appActions apps=apps />
      <Footer />
    </div>
  );
;

app/actions/apps.ts

export const getAppData = () => 
    let appKey = 'interpegasus';
    return (dispatch: Dispatch) => 
      dispatch(StatusActions.startAppLoading());
      debugger;
      apolloClient
        .query(
          query: gql`
            query getApp($appKey: String!) 
              getApp(id: $appKey) 
                id
                name
                domain
              
            
          `,
          variables: 
            appKey: appKey
          
        )
        .then((result) => 
          debugger;
          if (result.data.apps.length > 0) 
            dispatch(populateAppData(result.data.apps[0]));
          
          dispatch(StatusActions.endAppLoading());
        )
        .catch((error) => 
          dispatch(StatusActions.endAppLoading());
          console.log(
            error: error
          );
        );
    ;
  ;

【问题讨论】:

【参考方案1】:

你应该把你的 appActions.getAppData() 放在 useEffect 这样的钩子里

useEffect(()=>

 appActions.getAppData()

,[])

查看官方文档Introducing Hooks

【讨论】:

【参考方案2】:

Main/index.tsx 中,您正在调用appActions.getAppData();,这将引导您到actions/apps.ts。在这里,您正在执行dispatch(StatusActions.startAppLoading());,它将更新状态并重新渲染“Main/index.tsx”。然后再次调用 getAppData() 并且循环继续导致无限循环。

只有在不是loading时才调用api。

类似这样的:

  ...
  const  apps, loading  = useSelector((state: RootState) => 
    return 
      apps: state.apps,
      loading: state.loading // <----- replace with your actual name of your state 
    ;
  );

  if(!loading)
    appActions.getAppData();
  
  ...

【讨论】:

以上是关于如何在功能性 React JS 组件中获取数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何将从 API 获取的数据作为道具传递给其路由在 React JS 的另一个页面中定义的组件?

如何在 React 功能组件中获取表单/提交以使用 ReactStrap?

如何在 React 函数组件中不使用 useEffect 钩子获取数据?

如何使用功能方法(即非基于类)在 React js 中制作纯组件

无法将数据从子功能组件传递到反应父组件(React.js)[重复]

react js map功能无法渲染自定义组件