Обратный контекст API обратного вызова setState - PullRequest
0 голосов
/ 29 февраля 2020

Я успешно создал приложение React, используя концепцию Context API для управления глобальным состоянием, но теперь я столкнулся с проблемой, которая заключается в выполнении действия после вызова setState в компоненте Context из дочернего компонента.

У меня есть компонент на основе класса ListView, в котором есть компонент React Bootstrap NavDropdown. Компонент раскрывающегося списка содержит два элемента списка: дату и имя_исследования (я использую его для сортировки списка либо по дате, либо по_учению):

<NavDropdown title="Order By" id="order-nav-dropdown" style={navElementStyle} onSelect={this.onSelect}>

В том же компоненте ListView я иметь следующую функцию для захвата события onSelect NavDropdown:

onSelect = (e, obj) => {

    var match = obj.target.href.match(/#(.+)$/);

    if(this.context.state[match[1]] !== e){
        this.context.updateState(match[1],  e);
    }
  }

Для управления контекстом у меня есть отдельный компонент на основе классов с именем SearchContext, который имеет состояние:

state = {
  order_by: "study_id",  //default value study_id
  sort_by: "desc"        //default value of desc
}

В этом компоненте контекста у меня есть метод updateState:

updateState(key, value){
   this.setState({[key]: value});
}

Я не поместил здесь весь код компонентов, потому что он содержит много кода, но все работает отлично. Когда я изменяю раскрывающийся список в компоненте, состояние в SearchContext обновляется, и оно становится доступным, например, когда я маршрутизирую этот компонент в другой компонент, а затем снова возвращаюсь. Вот почему я сделал это. Я использую Маршрутизатор, чтобы щелкнуть по одному из элементов списка, чтобы просмотреть этот элемент, но затем, когда я go возвращаюсь к компоненту ListView, локальное состояние всегда будет потеряно, я полагаю, потому что оно полностью перезагружается?

В любом случае, после долгих исследований Context API был подходом, который я нашел, и, как я уже сказал ... он работает. Когда я возвращаюсь в ListView, раскрывающиеся списки сохраняют свои значения элементов списка.

Проблема теперь заключается в следующем:

До того, как я начал использовать ContextAPI, я использовал локальное состояние компонента ListView для прямого вызова setState, чтобы я мог передать обратный вызов, который затем получит результаты из базы данных, используя Ax ios (this.updateList - имя обратного вызова, обратный вызов здесь не показан). Это работало так:

onSelect = (e, obj) => {

    var match = obj.target.href.match(/#(.+)$/);

    if(this.state[match[1]] !== e){
        this.setState({[match[1]] :  e},  this.updateList);
    }
  }

Это позволило мне вызвать this.updateList после обновления локального состояния. Это работало нормально ... но теперь, когда я переместил состояние в компонент Context, я не могу использовать этот метод, потому что "this" относится к дочернему элементу ... а не к компоненту context. Поэтому я получаю неопределенный вызов метода.

Я провел много поисков в Google, и я сужусь к тому, что эта проблема может быть решена только с помощью хуков, но я не хочу go идти по этому пути, потому что должно быть более простой способ заставить это работать с подходом на основе классов, который я использую. Если мой подход не является полностью неправильным, и я не делаю это "React", я чувствую, что должен быть способ получить ту же функциональность setState и передать обратный вызов от дочернего элемента к родительскому ...

Если у кого-то есть предложения, я буду признателен. Я уверен, что в конечном итоге мне придется изучать хуки, но тот факт, что React существовал до хуков, заставляет меня думать, что к этому должен быть подход, основанный на классах.

Ответы [ 2 ]

0 голосов
/ 01 марта 2020

ОК, после небольшого исследования я наконец-то получил его. Не уверен, поможет ли это кому-либо, но это работает для меня.

Сначала в файле SearchContext я изменил функцию updateState (которая изменяет состояние контекста) со следующего:

updateState(key, value){
   this.setState({[key]: value});
}

на следующее:

  updateState(key, value){

    return new Promise((resolve) =>{
      this.setState({[key]: value}, ()=>{
         resolve('success!');
      });
    })
  }

Итак теперь функция updateState возвращает обещание.

Теперь, вернувшись в дочерний компонент, я изменил вызов функции updateState с этого:

    if(this.state[match[1]] !== e){
        this.setState({[match[1]] :  e},  this.updateList);
    }

на следующее:

    if(this.context.state[match[1]] !== e){
        //The selected state value has changed in the drop down list.
        this.context.updateState(match[1],  e).then((msg) =>{
           console.log(msg)
           this.updateList();
        });
    }

... и это работает как и ожидалось. Состояние SearchContext обновляется асинхронно, но, так как я возвращаю обещание, теперь я могу дождаться завершения операции, прежде чем вызывать функцию Ax ios, которая обновляет мой список на основе новой опции раскрывающегося списка.

Довольно круто, я очень рад, что мне не пришлось переписывать все с помощью хуков, и теперь я понимаю, как реализовать Promise.

0 голосов
/ 29 февраля 2020

Если я вас правильно понимаю, вы хотите установить состояние в родительском компоненте из компонента, находящегося ниже в дереве через контекст. Это абсолютно нормальная вещь, и вы на правильном пути.

Поместите вашу функцию updateState в ваш объект контекста. Проще всего будет получить доступ к объекту контекста через свойство context, используя contextType: https://reactjs.org/docs/context.html#classcontexttype

Примерно так:

import MyContextObject from './MyContextObject'; // defined in its own file

// define your ListView component here

ListView.contextType = MyContextObject

Тогда Получите доступ к своей функции updateState следующим образом:

this.context.updateState({key: value});

Примечание: contextType работает только с компонентами класса (это то, о чем вы просили), а все те статьи, которые вы читаете, говорят: «Вы должны использовать крючки ", вероятно, правы, крючки отличные! Как только вы освоитесь с React, посмотрите в Redux состояние приложения mgmt: https://redux.js.org

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...