Я разрабатываю календарь, используя реакцию и сокращение.
У меня есть родительский компонент (приложение), который передает свойства дочернего компонента (MonthlyCalendar), называемые событиями.
события - это объект. Каждое значение в событиях представляет собой массив. Любые события обновляются из 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
Я добавил forceUpdate в родительский компонент в componentDidUpdate, по-прежнему нет повторной визуализации дочернего компонента (MonthlyCalendar):
componentDidUpdate(prevProps: AppProps) {
const prevEvents = JSON.stringify(prevProps.events);
const currentEvents = JSON.stringify(this.props.events);
if ( prevEvents !== currentEvents) {
this.forceUpdate()
}
}
EDIT 2
возможно, проблема связана с маршрутом. Я читал статью о рендеринге компонента в маршруте: https://learnwithparam.com/blog/how-to-pass-props-in-react-router/#: ~: text = Передача% 20function% 20as% 20a% 20component% 20props% 20in% 20Route% 20component & text = Внутренне% 2C% 20react% 20router% 20use% 20React, просто% 20updating% 20the% 20existing% 20component.
добавлен рендеринг с props и {... props} все еще нет go:
<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>
EDIT 3
кажется, что если я выберу маршрут, все будет работать, и дочерний элемент будет перерисован. у кого-нибудь есть объяснение этому поведению?