简体   繁体   English

React 和 redux 使用异步数据获取

[英]React and redux usage with async data fetching

I have this action我有这个动作

export function fetchBranches() {
  return async dispatch => {
    const result = await axios.get('https://localhost:5002/Branches')
    dispatch({ type: FETCH_BRANCHES, payload: result.data.value })
  }
}

and such reducer和这样的减速机

export const branchReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_BRANCHES: {
      return { ...state, branches: action.payload }
    }
    default: return state
  }
}

In my component, I'm try to do such thing在我的组件中,我正在尝试做这样的事情

const dispatch = useDispatch()
dispatch(fetchBranches())
const branches = useSelector(state => state.branches.branches)

return <>
  some component that uses branches
</>

So my problem is i'm getting infinite number of request trying to fetch (I can see them in redux dev tools).所以我的问题是我收到了无数个尝试获取的请求(我可以在 redux 开发工具中看到它们)。 My page are not getting updated, but if go to other page and then return to one that tries perform this fetch, I'm can see values in store and at the page.我的页面没有更新,但是如果 go 到其他页面然后返回到尝试执行此提取的页面,我可以在商店和页面上看到值。 So questions are:所以问题是:

  1. Where and how should I dispatch actions to fetch some data to render it then?我应该在哪里以及如何调度操作来获取一些数据来呈现它?
  2. Why I'm getting that much requests and how can I fix it?为什么我收到这么多请求,我该如何解决?

UPD: Thanks a lot for your answers, but I still see behavior that my component rendered before I received data from api. UPD:非常感谢您的回答,但我仍然看到我的组件在收到来自 api 的数据之前呈现的行为。 I wanted to try useState and set state in useEffect , but I can't use useSelector .我想尝试useState并在 useEffect 中设置useEffect ,但我不能使用useSelector What should I do to re-render component as soon as my data loaded?加载数据后,我应该怎么做才能重新渲染组件?

UPD2: now my component look like UPD2:现在我的组件看起来像

function BranchList() {
  const [isLoaded, setIsLoaded] = useState(false)
  const dispatch = useDispatch()
  useEffect(() => {
    dispatch(fetchBranches())
    setIsLoaded(true)
  }, [])

  const branches = useSelector(state => state.branches.branches)
  const headerNames = ["Id", "Name"]

  if (!isLoaded) {
    return <>Loading...</>
  }
  
  return (
    <EditableTable
      data={branches}
      headerNames={headerNames}
      onEditConfirm={(row) => dispatch(updateBranch(row))}
      onDelete={(id) => dispatch(deleteBranch(id))} />
    )
  }

Dispatching generally should never be done directly in render, but in a useEffect or an event callback.调度通常不应该直接在渲染中完成,而是在useEffect或事件回调中完成。 In your case,在你的情况下,

const dispatch = useDispatch()
useEffect(() => { 
  dispatch(fetchBranches());
  }, 
  [dispatch]
)
const branches = useSelector(state => state.branches.branches)

Also please note that you are writing a pretty old style of redux here - please read the official tutorials to learn the recommended "modern" style of redux we are officially recommending.另请注意,您在这里写的是 redux 的相当旧的风格 - 请阅读官方教程以了解我们官方推荐的 redux 的推荐“现代”风格。 You'll end up writing a lot less code.你最终会编写更少的代码。

You should try putting your dispatch action into an useEffect, so the code will be only executed once like so:您应该尝试将调度操作放入 useEffect 中,这样代码将只执行一次,如下所示:

const dispatch = useDispatch()

React.useEffect(() => {
dispatch(fetchBranches())
}, [])

Documentation here .文档在这里

Your HTTP request action causes side effects in the component.您的 HTTP 请求操作会导致组件中的副作用。 Every state change causes re-rendering the component.每个 state 更改都会导致重新渲染组件。 To avoid side effects, you should use useEffect hook in your component.为避免副作用,您应该在组件中使用 useEffect 挂钩。

In your component,在您的组件中,

const dispatch = useDispatch()
const onFetchBranches = useCallback(() => dispatch(fetchBranches()), [dispatch]);

const branches = useSelector(state => state.branches.branches)

useEffect(() => {
  onFetchBranches();
}, [onFetchBranches]);

return <>
  some component that uses branches
</>

You should check Reactjs documentation to understand useEffect hook better.您应该查看 Reactjs 文档以更好地了解 useEffect 挂钩。 https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects

dispatch an action into useEffect hook to solve your issue.action dispatchuseEffect挂钩以解决您的问题。

Try:尝试:

useEffect(() => dispatch(fetchBranches()), [])

Perhaps if you try this:也许如果你试试这个:

function BranchList() {
  const [isLoaded, setIsLoaded] = useState(false)
  const dispatch = useDispatch()

  useEffect(() => {
    if(!isLoaded) {
        dispatch(fetchBranches())
            .then(() => setIsLoaded(true))
    }
    
  }, [isLoaded])

  const branches = useSelector(state => state.branches.branches)
  const headerNames = ["Id", "Name"]

  if (!isLoaded) {
    return <>Loading...</>
  }
  
  return (
    <EditableTable
      data={branches}
      headerNames={headerNames}
      onEditConfirm={(row) => dispatch(updateBranch(row))}
      onDelete={(id) => dispatch(deleteBranch(id))} />
    )
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM