Redux 状态加载,但反应不渲染

Posted

技术标签:

【中文标题】Redux 状态加载,但反应不渲染【英文标题】:Redux state loading, but react not rending 【发布时间】:2021-01-17 17:33:42 【问题描述】:

所以我从服务器端获取数据。状态在 redux 中加载,但 react 没有渲染处于状态的数组。

这是我的 react 组件:

import React,  useEffect, useState  from "react";
import  IonContent, IonButton, IonButtons, IonToolbar, IonTitle, IonHeader,  IonList  from "@ionic/react";
import  IInviteModal, IInviteReduxProps  from "../types/interfaces";
import  connect  from "react-redux";
import getInvites from '../flux/actions/eventActions';
import InviteListItem from "./InviteListItem";

const InviteModal = ( getInvites, invite, onDismissModal: IInviteModal) => 
  
// const [invites, setInvites] = useState();

  useEffect(() =>  
    getInvites(); 
  , [getInvites]);

  // const  invites  = invite;
  const invites  = ...invite

  const handleOnSubmit = (e: any) => 
      e.preventDefault();
 ;
    
  return (
        <IonContent>
          <form onSubmit=handleOnSubmit>
              <IonHeader>
              <IonToolbar>
                <IonButtons slot="start">
                    <IonButton 
                    onClick=onDismissModal
                    >
                        Back
                    </IonButton>
                </IonButtons>
              <IonTitle>
                <div className="ion-text-center">
                Event Invites
                </div>
              </IonTitle>
            </IonToolbar>
            </IonHeader>
            <IonList>
                
                invites ? 
                invites.map(invite => <InviteListItem 
                invite=invite
                key=invite._id
                />
                )
                : "Loading..."
              
            </IonList>
          </form>
          </IonContent>
  );
;

const mapStateToProps = (state: IInviteReduxProps) => (
  invite: state.invite
);

export default connect(mapStateToProps,  getInvites )(InviteModal);

import React from 'react';
import   IonItem, IonLabel, IonButton, IonGrid, IonRow, IonCol  from '@ionic/react';
import connect from 'react-redux';
import setCurrentI from '../flux/actions/eventActions';
import  IInviteListItem  from '../types/interfaces';
import format from "date-fns";
 
const InviteListItem = ( invite, setCurrentI : IInviteListItem) => 

  const setCurrentInvite = (invite: any) => setCurrentI(invite);

  return (
          <div>          
              <IonItem
              onClick=() => setCurrentInvite(invite)
              >
                <IonLabel>
                <h2>invite.title</h2>
                <p>invite.location</p>
                <br />
                <p>format(new Date(invite.dateStart), "MMM d', 'h:mm aaa")&mdash;&nbsp;
                  format(new Date(invite.dateEnd), "MMM d', 'h:mm aaa")</p>
                  /* <br /> */
                  <div className="ion-text-center">
                <IonGrid>
                  <IonRow>
                    <IonCol>
                      <IonButton size="small" fill="clear">
                      Accept
                      </IonButton>
                    </IonCol>
                    <IonCol>
                      <IonButton size="small" fill="clear">
                      _
                      </IonButton>
                    </IonCol>
                    <IonCol>
                      <IonButton size="small" fill="clear">
                      Decline
                      </IonButton>
                    </IonCol>
                  </IonRow>
                </IonGrid>
                </div>
                </IonLabel>
              </IonItem>
        </div>      
  );
;

export default connect(null, setCurrentI)(InviteListItem);

这是减速器:

import GET_EVENTS, GET_EVENT, ADD_EVENT, DELETE_EVENT, EVENTS_LOADING, UPDATE_EVENT, SET_CURRENT, CLEAR_CURRENT, LOG_ARRIVAL, EVENT_ERROR, GET_INVITES from '../actions/types';
import IAction, IEvent, IInvite from '../../types/interfaces';

const initialState = 
    events: [],
    invites: [],
    current: [],
    loading: false
;

interface IState 
    events: IEvent[];
    invites: IInvite[];
  
  
export default function(state: IState=initialState, action: IAction)
    switch(action.type)
        case GET_EVENTS:
            return
                ...state,
                events: action.payload,
                loading: false
            ;
        case GET_INVITES:
            return
                ...state,
                invites: action.payload,
                loading: false
            ;

Page not mapping array, state is loaded Diff redux output

页面只显示“正在加载...”

奇怪的是,我使用完全相同的结构来获取其他数据和数组映射而没有问题。

关于如何让数组渲染的任何想法?

这是有效的代码:

import React,  useEffect  from 'react';
import  IonContent, IonLabel, IonList  from '@ionic/react';
import connect from 'react-redux';
import getEvents from '../flux/actions/eventActions';
import  IEventReduxProps, ICalendar  from '../types/interfaces';
import EventListItem from './EventListItem';


const Calendar = ( getEvents, event : ICalendar) => 

  useEffect(() =>  
    getEvents(); 
  , [getEvents]);
 
  const  events  = event;

  return (
    <IonContent>
      <IonList>
          events.map(event => <EventListItem 
          event=event 
          key=event._id/>
          )
          
      </IonList>
    </IonContent>
  );
;

const mapStateToProps = (state: IEventReduxProps) => (
  event: state.event
);

export default connect(mapStateToProps,  getEvents )(Calendar);

import React from 'react';
import   IonItem, IonIcon, IonLabel, IonButton  from '@ionic/react';
import connect from 'react-redux';
import deleteEvent, setCurrent from '../flux/actions/eventActions';
import  IEventListItem  from '../types/interfaces';
import  closeCircle  from 'ionicons/icons';
import format from "date-fns";

const EventListItem = ( event, deleteEvent, setCurrent : IEventListItem) => 

  const handleDelete = (_id: string) => deleteEvent(_id);;
  const setCurrentEvent = (event: any) => setCurrent(event);;

  return (
          <div>          
              <IonItem  
              onClick=() => setCurrentEvent(event)
              // routerLink=`/event/$event._id`          
              >
                <IonLabel>
                <h2>event.title</h2>
                <p>event.location</p>
                <p>format(new Date(event.dateStart), "MMM d', 'h:mm aaa")&mdash;&nbsp;
                  format(new Date(event.dateEnd), "MMM d', 'h:mm aaa")</p>
                  /* MAP the ATTENDEES */
                  event.attendees.map((attendee, _id)=> (
                  <p key=attendee._id >
                    attendee.name
                    /* attendee.email */
                  </p>
                  )
                  )
                </IonLabel>
                <IonButton
                routerLink=`/event/log/$event._id`
                color="success"
                fill="clear"
                >Log</IonButton>
                
                <IonButton
                routerLink=`/event/$event._id`
                fill="clear"
                >Edit</IonButton>
                <IonIcon 
                    icon=closeCircle 
                    slot="end"
                    className="remove-btn"
                    color="danger"
                    onClick=() => handleDelete(event._id)
                    />
              </IonItem>
        </div>      
  );
;



export default connect(null,  deleteEvent, setCurrent )(EventListItem);

【问题讨论】:

您能否为getInvites 提供reducer 并使用redux 开发工具(标签差异)进行截图? getInvites 一个已经绑定到你的 redux store 的函数吗?尝试用connect(mapStateToProps, dispatch =&gt; bindActionCreators( getInvites ))(InviteModal);替换connect(mapStateToProps, getInvites )(InviteModal); @KirillSkomarovskiy 完成,我还添加了可以正常工作的代码。 @JacobSmit 在尝试您的 getInvites 解决方案时出错:“未提供 'dispatch' 的参数” 抱歉,我离开了一个星期。 bindActionCreators( getInvites ) 应该包含 dispatch 作为第二个参数 bindActionCreators( getInvites , dispatch) 【参考方案1】:

如果redux store 中有数据,则必须从react-redux 添加useSelector()

这样,当新的props 进入应用程序时,您将通知组件,这将导致组件向re-render 发送新数据。

还有一个问题是你同时使用import connect from "react-redux";hooks

您必须决定是要将reduxhooks 一起使用还是class

如果你想将它与钩子一起使用,那么你需要:useSelectoruseActions

如果你想将它与类组件一起使用,那么你需要来自 redux:mapStateToPropsmapDispatchToPropsconnect

简而言之:您正在混合两种不同的方法。

【讨论】:

【参考方案2】:

我想你在connect 上遇到了一些问题。 HOC connect 有 4 个参数。一个特别的options 我没有发现你的问题。你能试试下面的两个组件吗?

如果这段代码没有帮助 - 我认为你的问题在于减速器、动作、中间件。

InviteModal.tsx

import React from 'react';
import  useSelector, useDispatch  from 'react-redux';
import  IonContent, IonButton, IonButtons, IonToolbar, IonTitle, IonHeader,  IonList  from '@ionic/react';

import  getInvites  from '../flux/actions/eventActions';

import  IInviteModal, IInviteReduxProps  from '../types/interfaces';
import InviteListItem from './InviteListItem';
/* TODO: make correct IInviteModal */
const InviteModal: React.FC<IInviteModal> = ( onDismissModal ) => 
  const dispatch = useDispatch();
  const  invites  = useSelector(( invite : IInviteReduxProps) => invite);

  React.useEffect(() =>  
    dispatch(getInvites());
  , [dispatch]);

  const handleOnSubmit = React.useCallback((e: any) => 
    e.preventDefault();
  , []);
    
  return (
    <IonContent>
      <form onSubmit=handleOnSubmit>
        <IonHeader>
          <IonToolbar>
            <IonButtons slot="start">
              <IonButton onClick=onDismissModal>
                Back
              </IonButton>
            </IonButtons>
            
            <IonTitle>
              <div className="ion-text-center">
                Event Invites
              </div>
            </IonTitle>
          </IonToolbar>
        </IonHeader>

        <IonList>
          
          invites
            ? invites.map(invite => <InviteListItem invite=invite key=invite._id />)
            : "Loading..."
          
        </IonList>
      </form>
    </IonContent>
  );
;

export default InviteModal;

InviteListItem.tsx

import React from 'react';
import   IonItem, IonLabel, IonButton, IonGrid, IonRow, IonCol  from '@ionic/react';
import  useDispatch  from 'react-redux';
import  format  from 'date-fns';

import  setCurrentI  from '../flux/actions/eventActions';

import  IInviteListItem  from '../types/interfaces';

const formatData = (data: string) => format(new Date(data), "MMM d', 'h:mm aaa");
/* TODO: make correct IInviteListItem */
const InviteListItem: React.FC<IInviteListItem> = ( invite ) => 
  const dispatch = useDispatch();
  const setCurrentInvite = React.useCallback(() => 
    dispatch(setCurrentI(invite));
  , [invite, dispatch]);

  return (
    <IonItem onClick=setCurrentInvite>
      <IonLabel>
        <h2>invite.title</h2>
        
        <p>invite.location</p>
        
        <br />
        
        <p>
          formatData(invite.dateStart)
          &mdash;&nbsp;
          formatData(invite.dateEnd)
        </p>

        <div className="ion-text-center">
          <IonGrid>
            <IonRow>
              <IonCol>
                <IonButton size="small" fill="clear">
                  Accept
                </IonButton>
              </IonCol>

              <IonCol>
                <IonButton size="small" fill="clear">
                  _
                </IonButton>
              </IonCol>
              
              <IonCol>
                <IonButton size="small" fill="clear">
                  Decline
                </IonButton>
              </IonCol>
            </IonRow>
          </IonGrid>
        </div>
      </IonLabel>
    </IonItem>
  );
;

export default InviteListItem;

【讨论】:

这会在我正在渲染的主页上引发各种错误。 @morethan1 你能提供屏幕或文字吗? 你是对的,这与我的减速器有关。我为 Invites 创建了单独的减速器和操作,现在一切正常。谢谢

以上是关于Redux 状态加载,但反应不渲染的主要内容,如果未能解决你的问题,请参考以下文章

更新 Redux 存储时反应组件不重新渲染

如何在反应中使用redux中的布尔状态值渲染组件?

将新的商店状态放入道具后,反应不会重新渲染

反应父组件不重新渲染

渲染后调用的函数反应原生

将数组从 redux 存储导入到表中。反应,js