WedX - журнал о программировании и компьютерных науках

Реагировать на то, чтобы не выполнять повторный рендеринг компонента после обновления страницы, даже если состояние изменилось.

У меня действительно странная проблема. Я имею в виду, на самом деле для меня. Это не проблема типа «использовать 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>
    );
    }
}


31.08.2019

  • в Schedule.js вы используете this.trip. Как это установить? 31.08.2019

Ответы:


1

Вы мутируете свое состояние. В этом месте вы изменяете объект в состоянии без использования setState:

newTrip.days = newTrip.days.filter(day => day.id !== id)

И затем в своей функции карты вы всегда возвращаете одни и те же объекты (они уже обновлены). Итак, чтобы решить вашу проблему, вы можете попробовать изменить свой deleteDay метод:

   deleteDay = (id, tripId) => {
        const trip = this.state.userData.trips.find((trip => trip.id === 
         tripId));
        const newTrip = {...trip, days: trip.days.filter(day => day.id !== id)};

        this.updateTrip(newTrip);
    }

ОБНОВЛЕНИЕ: у вас есть еще одна проблема в вашем Schedule компоненте.

Текущее путешествие нужно получать динамически, не устанавливайте его в конструкторе:

Попробуй это:

constructor(props) {
    super(props);
    this.getTrip = this.getTrip.bind(this);
}
getTrip() {
    return this.props.context.userData.trips.find(trip => {
        return `${trip.id}`===this.props.match.params.id;
    });
}
render() {
    const trip = this.getTrip();

    return (
        ...
        <ul>
            {trip.days.map((day,index) => {
                return <DayWithContext 
                    inOverview={false} 
                    key={day.id} 
                    number={index} 
                    day={day} 
                    tripId={trip.id}    
                />
            })}
        </ul>
        ...
    )
}
31.08.2019
  • Спасибо за ответ - я забыл, что = не копирует массив. Я исправил это, используя: const trips = Array.from (this.state.userData.trips); let newTrip = trips.find ((trip = ›trip.id === tripId)); Но это все равно не решило мою проблему. Состояние контекста обновляется, но компонент расписания остается прежним. Когда я впервые вижу приложение после входа в систему - оно работает нормально. Но когда я обновляю страницу (сеанс держит меня в системе) и делаю то же действие с любым другим элементом в списке, ничего не происходит. Состояние за занавесом меняется, но рендеринг не запускается ... 31.08.2019
  • @hayanawama, код, который вы только что показали, не решает проблему с мутацией данных. Если вы попытаетесь изменить переменную newTrip после кода, вы также измените поездку в своем состоянии. Попробуйте этот код: const arr = [{foo: "bar"}]; const newArr = Array.from(arr); newArr[0].foo = "baz"; console.log(arr[0].foo); (извините за форматирование, комментарии не позволяют использовать красивое форматирование) Видите ли, Array.from не создает новые объекты, а просто копирует ссылки на исходные. Вам нужно сделать то же самое, что я показываю в своем ответе, вам нужно создать новый объект для вашего newTrip. 31.08.2019
  • @hayanawama, а также потенциальную ошибку, которую я вижу в вашем Schedule.js. Вам необходимо использовать day.id в качестве ключа для вашего компонента: key={day.id} 31.08.2019
  • О, так меня ввел в заблуждение какой-то веб-сайт с Array.from. Я сделал все, что вы сказали, а также изменил первую строку в updateTrip на const trips = [... this.state.userData.trips]. Все еще не работает. Я тоже поменял ключ (почему, кстати?). Если вы все еще готовы помочь, вы можете проверить мою заметку об обновлении в нижней части основного вопроса - проблема в другом месте, потому что состояние изменено, компонент получает новые реквизиты, но он не отображается повторно: / 31.08.2019
  • @hayanawama, о ключах проверьте React doc 31.08.2019
  • Вот репозиторий github с расписанием: github.com/hayanawama/tripPlannerProject/blob/master/ 31.08.2019
  • Также я упростил объяснение того, что происходит в структуре моего приложения, для лучшего и простого понимания. В «Дневном компоненте» тоже есть «Действия», но неважно, удаление того или другого дает ту же ошибку. 31.08.2019
  • Спасибо чувак!!!!!!!!!!! Теперь работает как шарм. Сделал вашу функцию стрелочной, но без привязки в конструкторе. Спасибо за уделенное время, я многому научился из этого разговора. Похоже, мне нужно много читать о жизненном цикле компонентов и React в целом. Но теперь я не понимаю, почему это вообще сработало (без обновления страницы), так как отключение было постоянно исправлено: D Еще один вопрос, приведет ли размещение функции внутри shouldComponentUpdate с таким же эффектом? 31.08.2019
  • @hayanawama, вы можете разместить любую функцию внутри shouldComponentUpdate. Единственное, что вам следует знать о shouldComponentUpdate, это то, что первым параметром будет newProps, а старые реквизиты могут получить доступ через this.props. Итак, если вы определите что-то вроде getTrip внутри shouldComponentUpdate, вы получите только старый trip. 01.09.2019
  • Новые материалы

    Как создать диаграмму градиентной кисти с помощью D3.js
    Резюме: Из этого туториала Вы узнаете, как добавить градиентную кисть к диаграмме с областями в D3.js. Мы добавим градиент к значениям SVG и применим градиент в качестве заливки к диаграмме с..

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

    Лицензии с открытым исходным кодом: руководство для разработчиков и создателей
    В динамичном мире разработки программного обеспечения открытый исходный код стал мощной парадигмой, способствующей сотрудничеству, инновациям и прогрессу, движимому сообществом. В основе..

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..


    Для любых предложений по сайту: [email protected]