У меня действительно странная проблема. Я имею в виду, на самом деле для меня. Это не проблема типа «использовать setState вместо this.state». Я работаю над приложением для планирования поездок. Я использую ContextAPI, который предоставляет информацию для входа и пользовательские данные (зарегистрированные пользовательские поездки и т. Д.) Для всего приложения. Компонент «Расписание», отображающий расписание поездок по дням, является контекстным подписчиком. Теперь я хочу удалить один из дней поездки (день, также подписка на контекст - это компонент, отображаемый компонентом расписания в списке расписания). И тут происходит волшебство:
когда я делаю это сразу после входа в приложение, все работает нормально. Но когда я обновлю страницу и удалю другой день, состояние контекста (которое, как я уже сказал, содержит все данные, включая список дней по расписанию) изменится (проверено с помощью инструментов разработчика), но компонент расписания не перерисовывает себя, поэтому удаленный элемент остается видимым. Но, как я уже сказал, состояние меняется, и все работает нормально без обновления страницы перед удалением операции. Также, когда я переключаюсь на другую вкладку («Расписание» - это всего лишь одна из вкладок, у меня есть, например, вкладка «Затраты и примечания» на панели навигации, отображающие компоненты «Затраты и заметки»), а затем возвращаюсь на вкладку «Расписание», которую он повторно отображает, и все остальное. выглядит нормально, компонент отображает информацию в соответствии с состоянием контекста.
Код работает следующим образом: удаление (функция контекста) запускается щелчком значка удаления в Day.js (контекстный подписчик), Day.js отображается с помощью Schedule.js (также контекстный подписчик).
В Context.js
... context functions ...
//WRAPPER FOR DELETE FUNCTIONS
delete(url, deleteFunc) {
this.requestsApi.request(url, "DELETE", null)
.then(response => {
if(response.status===204) {
deleteFunc();
} else {
this.toggleRequestError(true);
}
})
.catch( err => {
console.log(err);
this.toggleRequestError(true);
});
}
deleteDay = (id, tripId) => {
let newTrip = this.state.userData.trips.find((trip => trip.id ===
tripId));
newTrip.days = newTrip.days.filter(day => day.id !== id)
this.updateTrip(newTrip);
}
updateTrip = (newTrip) => {
let trips = this.state.userData.trips;
this.setState(prevState => ({
userData : {
...prevState.userData,
trips: trips.map(trip => {
if(trip.id !== newTrip.id)
return trip;
else
return newTrip;
})
}
}
));
}
...
В Schedule.js
... in render's return ...
<ul>
{this.trip.days.map((day,index) => {
return <DayWithContext
inOverview={false}
key={index}
number={index}
day={day}
tripId={this.trip.id}
/>
})}
</ul>
....
В Day.js (значок удаления)
...
<img
src={Delete}
alt="Delete icon"
className="mr-2"
style={this.icon}
onClick={() => {
this.props.context.delete(
`/days/${this.props.day.id}`,
() => this.props.context.deleteDay(this.props.day.id,
this.props.tripId)
);
}}
/>
...
Кто-нибудь знает, что происходит и почему расписание не может быть повторно отображено после удаления, выполненного после обновления страницы? И даже если состояние контекста изменится? Единственная идея, которая у меня есть на данный момент, заключается в том, что это какая-то ошибка ...
// ОБНОВЛЕНИЕ В компоненте Расписание, в функции componentWillReceiveProps () я консоль логирую props.context.trip [0] .day [0] - первый день. Это не объект, а просто текст, поэтому он не оценивается, «когда я нажимаю на него в консоли». Прежде чем я его удалю, консоль регистрирует первый элемент. После того, как я удалю его, консоль регистрирует второй элемент (так что теперь это первый элемент в списке), так что реквизиты, заданные расписанию, меняются, но рендеринг не запускается ... Что, черт возьми, там происходит?
// ОБНОВЛЕНИЕ 2 Я также заметил, что когда я переключаюсь на компонент «Расписание» из другого компонента, он работает хорошо (например, я обновляю страницу в конечной точке / cost, затем щелкаю вкладку «Расписание» в меню панели навигации, что ведет к / schedule). Но когда я обновляю страницу при включении / расписании конечной точки, возникает эта «ошибка», и компонент не выполняет повторный рендеринг.
// Рендеринг из контекста:
...
render() {
const {
isLoggedIn,
wasLoginChecked,
userData,
isLogoutSuccesfulActive,
isLogoutUnSuccesfulActive,
isDataErrorActive,
isRequestErrorActive,
isDataLoaded
} = this.state;
const context = {
isLoggedIn,
wasLoginChecked,
isLogoutSuccesfulActive,
isLogoutUnSuccesfulActive,
isDataErrorActive,
isRequestErrorActive,
userData,
isDataLoaded,
requestsApi : this.requestsApi,
toggleLogin : this.toggleLogin,
checkLogin: this.checkLogin,
setUserData: this.setUserData,
loadData: this.loadData,
addTrip: this.addTrip,
delete: this.delete,
deleteDay: this.deleteDay,
deleteActivity: this.deleteActivity,
deleteTrip: this.deleteTrip,
updateTrip: this.updateTrip,
uncheckLogin: this.uncheckLogin,
toggleLogoutSuccesful: this.toggleLogoutSuccesful,
toggleLogoutUnSuccesful: this.toggleLogoutUnSuccesful,
toggleRequestError: this.toggleRequestError,
toggleDataError: this.toggleDataError
};
return (
<Context.Provider value={context}>
{this.props.children}
</Context.Provider>
)
}
}
export const Consumer = Context.Consumer;
------------- Контекст HOC:
export default function withContext(Component) {
return function ContextComponent(props) {
return (
<Context.Consumer>
{context => <Component {...props} context={context} />}
</Context.Consumer>
);
}
}
newTrip
после кода, вы также измените поездку в своем состоянии. Попробуйте этот код:const arr = [{foo: "bar"}]; const newArr = Array.from(arr); newArr[0].foo = "baz"; console.log(arr[0].foo);
(извините за форматирование, комментарии не позволяют использовать красивое форматирование) Видите ли,Array.from
не создает новые объекты, а просто копирует ссылки на исходные. Вам нужно сделать то же самое, что я показываю в своем ответе, вам нужно создать новый объект для вашегоnewTrip
. 31.08.2019day.id
в качестве ключа для вашего компонента:key={day.id}
31.08.2019shouldComponentUpdate
. Единственное, что вам следует знать оshouldComponentUpdate
, это то, что первым параметром будетnewProps
, а старые реквизиты могут получить доступ черезthis.props
. Итак, если вы определите что-то вродеgetTrip
внутриshouldComponentUpdate
, вы получите только старыйtrip
. 01.09.2019