Как повторно отрендерить React Component при вызове внешней функции? - PullRequest
0 голосов
/ 28 июня 2019

Я хочу получать сообщения mqtt и отображать их в веб-приложении. Я работаю с AWS Amplify PubSub, и вызовы функций происходят вне компонента класса. Я не могу напрямую получить доступ к какой-либо функции / свойствам экземпляра из функции за ее пределами, но мне нужен какой-то способ инициировать изменение setState, чтобы веб-приложение можно было повторно обработать, верно?

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

Опять же, все, что я действительно пытаюсь сделать, это получить сообщение и обновить веб-приложение для отображения нового сообщения. Звучит довольно просто, но я застрял.

import...

var itemsArr = [];

function subscribe() {
    // SETUP STUFF
    Amplify.configure({
        ...
    });
    Amplify.addPluggable(new AWSIoTProvider({
        ...
    }));

    // ACTUAL SUBSCRIBE FUNCTION
    Amplify.PubSub.subscribe('item/list').subscribe({
        next: data => {
        // LOG DATA
        console.log('Message received', data);

        // GET NAMES OF ITEMS
        var lineItems = data.value.payload.lineItems;
        lineItems.forEach(item => itemsArr.push(item.name));
        console.log('Items Ordered', itemsArr);

        // THIS FUNCTION CALL TRIGGERS AN ERROR
        // CANT ACCESS THIS INSTANCE FUNCTION
        this.update(itemsArr);
    },
        error: error => console.error(error),
        close: () => console.log('Done'),
    });
}

// REACT COMPONENT
class App extends Component {
    constructor(props){
        super(props);

        this.state = {
            items:null,
        };
    }

    // THOUGHT I COULD USE THIS TO UPDATE STATE
    // TO TRIGGER A RE-RENDER
    update(stuff){
        this.setState({items: stuff});
    }

    render() {
        // THINK SUBSCRIBE METHOD CALL SHOULDN'T BE HERE
        // ON RE-RENDER, KEEPS SUBSCRIBING AND GETTING
        // SAME MESSAGE REPEATEDLY
        subscribe();
        console.log('items down here', itemsArr);

        return (
            <div className="App">
                <h1>Test</h1>
                <p>Check the console..</p>
                <p>{itemsArr}</p>
            </div>
        );
    }
}
export default App;

В идеале, я хотел бы, чтобы столбцы списка элементов отображались при поступлении сообщений, но в настоящее время я получаю сообщение об ошибке - «Ошибка типа: не удается прочитать свойство« обновление »из неопределенного», поскольку функция подписки вне функции класс не имеет доступа к функции обновления внутри класса.

1 Ответ

0 голосов
/ 28 июня 2019

Поместите метод подписки в компонент приложения, чтобы вы могли вызывать его. Вы можете вызвать метод подписки в жизненном цикле componentDidMount, чтобы выполнить его (чтобы получить элементы) после первой визуализации компонента App. Затем метод update запустит this.setState () (для хранения ваших элементов в состоянии), что приведет к повторному рендерингу компонента App. Из-за этого повторного рендеринга ваш this.state.items будет содержать что-то, и это будет отображаться в вашем абзаце.

class App extends Component {
  constructor(props){
    super(props);

    this.state = {
        items: [],
    };

    this.subscribe = this.subscribe.bind(this); 
    this.update = this.update.bind(this);
  }

  update(stuff){
    this.setState({ items: stuff });
  }

  subscribe() {
    // SETUP STUFF
    Amplify.configure({
      ...
    });
    Amplify.addPluggable(new AWSIoTProvider({
      ...
    }));

    // ACTUAL SUBSCRIBE FUNCTION
    Amplify.PubSub.subscribe('item/list').subscribe({
      next: data => {
      // LOG DATA
      console.log('Message received', data);

      // GET NAMES OF ITEMS
      let itemsArr = [];
      var lineItems = data.value.payload.lineItems;
      lineItems.forEach(item => itemsArr.push(item.name));
      console.log('Items Ordered' + [...itemsArr]);
      this.update(itemsArr);
    },
      error: error => console.error(error),
      close: () => console.log('Done'),
    });
  }

  componentDidMount() {
    this.subscribe();
  }

  render() {

    console.log('items down here ' + [...this.state.items]);

    return (
        <div className="App">
            <h1>Test</h1>
            <p>Check the console..</p>
            <p>{this.state.items !== undefined ? [...this.state.items] : "Still empty"}</p>
        </div>
    );
  }
}

export default App;
...