【问题标题】:React and redux usage with async data fetchingReact 和 redux 使用异步数据获取
【发布时间】:2021-04-11 13:43:59
【问题描述】:

我有这个动作

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

还有这样的减速器

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

在我的组件中,我正在尝试做这样的事情

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

return <>
  some component that uses branches
</>

所以我的问题是我收到了无数个尝试获取的请求(我可以在 redux 开发工具中看到它们)。 我的页面没有得到更新,但是如果转到其他页面然后返回到尝试执行此提取的页面,我可以在商店和页面上看到值。所以问题是:

  1. 然后我应该在哪里以及如何调度操作来获取一些数据来呈现它?
  2. 为什么我会收到这么多请求,我该如何解决?

更新: 非常感谢您的回答,但我仍然看到我的组件在我从 api 接收数据之前呈现的行为。我想尝试useState 并在useEffect 中设置状态,但我不能使用useSelector。加载数据后,我应该怎么做才能重新渲染组件?

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))} />
    )
  }

【问题讨论】:

  • 您能提供您的组件的完整样本吗?你考虑过 useEffect 钩子吗?

标签: reactjs redux


【解决方案1】:

调度通常不应该直接在渲染中完成,而是在useEffect 或事件回调中完成。 在你的情况下,

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

另外请注意,您在这里写的是相当古老的 redux 风格 - 请阅读official tutorials 了解我们官方推荐的推荐的“现代”风格的 redux。你最终会编写更少的代码。

【讨论】:

    【解决方案2】:

    也许你试试这个:

    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))} />
        )
      }
    

    【讨论】:

    • 非常感谢,我已经很接近了。我的代码有什么区别?由于.then() 或我错过了useEffect 的依赖关系,它按我的预期工作?
    • 在依赖数组中使用 isLoaded 来实现 useEffect 可能是最重要的变化
    • .then 会阻止 setIsLoaded 函数被调用,直到异步调度(fetchBranches())得到解决。
    【解决方案3】:

    您的 HTTP 请求操作会在组件中产生副作用。每个状态更改都会导致重新渲染组件。为避免副作用,您应该在组件中使用 useEffect 挂钩。

    在您的组件中,

    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
    </>
    

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

    【讨论】:

      【解决方案4】:

      dispatch 一个 actionuseEffect 挂钩来解决您的问题。

      试试:

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

      【讨论】:

        【解决方案5】:

        您应该尝试将您的调度操作放入 useEffect 中,这样代码将只执行一次,如下所示:

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

        文档here

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-04-08
          • 1970-01-01
          • 2020-10-28
          • 2023-04-05
          • 1970-01-01
          相关资源
          最近更新 更多