我正在使用react和redux开发日历。
我有一个父组件(App),该组件传递给称为事件的子组件(MonthlyCalendar)道具。
events是一个对象。 事件中的每个值都是一个数组。 任何事件都将从redux更新,请重新渲染使用事件的父组件,而不是子组件。
子组件的第一个生命周期是唯一运行的生命周期,此后没有更新生命周期。即使道具已从空对象变为具有属性的对象。 我看到这是一个已知的问题-对象道具,但是没有一个解决方案起作用。 如果重复,对不起,我觉得我都尝试了。
我尝试对孩子和父母中的事件进行破坏。
我尝试使用JSON.parse和stringfy。
根据孩子中事件道具的长度添加一个键。
我删除了所有setState和可能会操纵状态的动作,仍然重新渲染了父级,但未渲染子级。 该检查由子组件每个生命周期的console.log完成,该子组件在安装时仅被打印一次。并且在调试时显示更新后的事件到达父级的渲染功能。
父组件-App.tsx
class App extends React.Component<AppProps> {
state = {
events: {},
weekStarter: 'sunday',
isTimeShown: true,
isTimeZoneShown: true,
isTodayButtonStyleSeconday: true,
locale: 'en',
timeZone: '',
};
constructor(props: any) {
super(props);
this.fetchEvents = this.fetchEvents.bind(this);
}
componentDidMount() {
window.Wix.Styles.getStyleParams((styleParams: any) => {
this.updateStyle(styleParams);
console.log('getStyleParams', styleParams);
});
window.Wix.addEventListener(
window.Wix.Events.STYLE_PARAMS_CHANGE,
(styleParam: Object) => {
console.log('STYLE_PARAMS_CHANGE', styleParam);
this.updateStyle(styleParam);
},
);
}
...
render() {
const { t, events } = this.props;
return (
<Switch>
<Route
path="/index"
render={() => (
<MonthlyCalendar
weekStarter={this.state.weekStarter}
events={{...events}}
handleMonthChange={handleMonthChange}
isTimeZoneShown={this.state.isTimeZoneShown}
isTimeShown={this.state.isTimeShown}
locale={this.state.locale}
//timeZone={this.state.timeZone}
isTodayButtonStyleSeconday={this.state.isTodayButtonStyleSeconday}
/>
)}
></Route>
<Route
path="/settings"
render={() => (
<Settings
fetchEvents={this.fetchEvents}
initialState={this.props.initialState}
weekStarter={this.state.weekStarter}
/>
)}
></Route>
<Route
path="/mobile"
render={() => (
<MonthlyCalendar
weekStarter={this.state.weekStarter}
events={events}
handleMonthChange={handleMonthChange}
isTimeZoneShown={this.state.isTimeZoneShown}
isTimeShown={this.state.isTimeShown}
locale={this.state.locale}
isTodayButtonStyleSeconday={this.state.isTodayButtonStyleSeconday}
/>
)}
></Route>
</Switch>
);
}
}
const mapDispatchToProps = (dispatch: any) => ({});
const mapStateToProps = (state: any) => ({
isConnect: state.settings.isConnect,
userName: state.settings.userName,
events: state.settings.dates,
calendarsList: state.settings.calendarsList,
googleSettings: state.settings.googleSettings,
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
孩子-MonthlyCalendar.tsx
class MonthlyCalendar extends React.Component<
IMonthylCalendarProps & WithTranslation,
IMonthylCalendarState
> {
monthlyCalendarRef: React.RefObject<HTMLDivElement>;
public static defaultProps = {
locale: 'en',
weekStarter: WeekStartersEnum.Sunday,
events: [],
isTimezonesOpen: true,
isTodayButtonStyleSeconday: true,
isTimeZoneShown: true,
isTimeShown: true
};
constructor(props: any) {
super(props);
console.log('[constructor] props.events: ',props.events)
const timezone = moment.tz.guess();
const dateObject = moment().tz(timezone, true);
this.state = {
dateObject,
timezone,
isTimezonesOpen: false,
};
}
shouldComponentUpdate(nextProps, nextState) {
console.log('[shouldComponentUpdate] props.events: ',this.props.events)
return true
}
...
getCalendar() {
const mutableEvents = {...this.props.events};
const { dateObject } = this.state;
const beforeFillers = this.getMonthBeforFillers(dateObject, mutableEvents);
const days = this.getDays(dateObject, mutableEvents);
const afterFillers = this.hasAfterFillers(beforeFillers, days) ?
this.getAfterMonthFillers(dateObject, mutableEvents) : {};
return { days, beforeFillers, afterFillers };
}
async componentDidUpdate(prevProps) {
console.log('[componentDidUpdate] props.events: ',this.props.events)
this.props.locale !== prevProps.locale && await this.updateLocale();
}
async componentDidMount() {
console.log('[componentDidMount] props.events: ',this.props.events)
this.props.locale !== 'en' && await this.updateLocale();
}
render() {
const { t, weekStarter, isTodayButtonStyleSeconday, isTimeZoneShown, isTimeShown, events: propEvents } = this.props;
const eventsKey = Object.keys(propEvents).length;
const { dateObject, timezone, isTimezonesOpen } = this.state;
const { days, beforeFillers, afterFillers } = this.getCalendar();
const month = dateObject.format(t('Google_Calendar_Picker_Month'));
const timezoneSelected = moment().tz(timezone).format(t('Google_Calendar_Timezone_Selected'));
const timezoneSelectedTitle = t('Google_Calendar_Timezone_Selected_Title', { timezoneSelected });
console.log('[render] props.events: ',this.props.events)
return (
<TPAComponentsProvider value={{ mobile: false, rtl: false }}>
<div key={eventsKey} className={classes.MonthlyCalendar}>
<CalendarControllers
isTodayButtonStyleSeconday={isTodayButtonStyleSeconday}
todayClicked={this.todayClickedHander}
onPreviousClicked={() => this.timePickerClickedHandler(false)}
timeToDisplay={month}
onNextClicked={() => this.timePickerClickedHandler(true)}
onTimezoneChange={this.timezoneChangeHandler}
timezone={timezoneSelectedTitle}
isTimezonesOpen={isTimezonesOpen}
openTimezones={this.openTimezones}
closeTimezones={this.closeTimezones}
isTimeZoneShown={isTimeZoneShown}
/>
<MonthTable
weekStarter={weekStarter}
days={days}
beforeFillers={beforeFillers}
dateObject={dateObject}
afterFillers={afterFillers}
renderCell={(
time: any,
events: any,
cellRef: any,
handleEventClick: any,
setExpendedEvent: any,
expendedEvent: any,
isOutsideClicked: any,
) => (
<MonthlyCell
events={events}
handleEventClick={handleEventClick}
time={time}
cellRef={cellRef}
expendedEvent={expendedEvent}
isOutsideClicked={isOutsideClicked}
setExpendedEvent={setExpendedEvent}
isTimeShown={isTimeShown}
/>
)}
/>
</div>
</TPAComponentsProvider>
);
}
}
export default withTranslation()(MonthlyCalendar);
任何帮助将不胜感激
编辑1
i在componentDidUpdate上将forceUpdate添加到了父组件,但仍然没有重新呈现子组件(MonthlyCalendar):
componentDidUpdate(prevProps: AppProps) {
const prevEvents = JSON.stringify(prevProps.events);
const currentEvents = JSON.stringify(this.props.events);
if ( prevEvents !== currentEvents) {
this.forceUpdate()
}
}
编辑2
中的渲染组件的文章添加了带有props和{... props}的渲染器仍然无法执行:
<Switch>
<Route
path="/index"
render={(props: any) => (
<MonthlyCalendar
{...props}
weekStarter={this.state.weekStarter}
events={{...this.state.events}}
handleMonthChange={handleMonthChange}
isTimeZoneShown={this.state.isTimeZoneShown}
isTimeShown={this.state.isTimeShown}
locale={this.state.locale}
//timeZone={this.state.timeZone}
isTodayButtonStyleSeconday={this.state.isTodayButtonStyleSeconday}
/>
)}
></Route>
编辑3
看来,如果我走这条路线,一切正常,孩子会重新渲染。有人对此行为有解释吗?