Как предупредить ребенка после завершения вызова выборки родительского компонента? ReactJS - PullRequest
0 голосов
/ 10 февраля 2020

Обзор:

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

Хитрость в том, что я должен иметь доступ к этим знаниям внутри дочернего процесса извне метода рендеринга (например, componentDidMount ()).

Справочная информация:

Мне нужно сделать таким образом, я могу вызвать функцию (которую я импортирую), так как:

1) функция, которую я хочу вызвать, обновит состояние, вызывая бесконечный рендер l oop, если вызывается внутри рендера

И

2) причина, по которой мне нужно проверить, был ли выполнен вызов выборки, заключается в том, что я передаю данные из вызова выборки (через контекст) в функцию в качестве параметров

Я выполняю вызов выборки в своем коде, и у меня есть переменная с именем «fetched», которая сохраняется как «false» до тех пор, пока выборка не будет завершена, затем «fetched» сохраняется как «true». Внутри обещания я устанавливаюTimeout на секунду, потому что в противном случае обещание будет выполнено до завершения вызова извлечения, поэтому обещание будет выполнено до того, как «извлеченные» могут быть обновлены до true. Я выбрал только «разрешить» и никогда не «отклонять», потому что мне нужно знать, когда завершился вызов извлечения. Таким образом, «разрешение» обещания вложено в условный оператор (который возвращает true, если «fetched» имеет значение true).

Ситуация:

1) Среди других значений состояния у меня есть свойство состояния с именем «fetch», которое по умолчанию установлено как «false». Цель этого свойства состояния состоит в том, чтобы оценивать его как «true» после завершения вызова выборки.

2) В моем файле приложения. js я выполняю вызов выборки для базы данных.

3) Внутри цепочки ".then", как только будет произведен вызов извлечения. Затем я устанавливаю для свойства состояния ("fetched") значение true.

4) У меня есть метод с именем "checkFetch", который возвращает обещание. Обещание разрешается только и разрешается, только если «fetched» имеет значение true, кроме того, все внутри обещания оборачивается в setTimeout на 1 секунду (таким образом я даю время для обновления свойства «fetched»).

5) В render () я передаю метод "checkFetch" в контекст (для доступа к дочернему компоненту).

6) В файле ViewSchedule. js (child), я сделать componentDidMount () асин c функцией. Внутри ComponentDidMount я жду "checkFetch ()", используя контекст.

ВОПРОС:

Это моя проблема: если я не установлю тайм-аут внутри обещания, то ничего не произойдет (как и ожидалось), потому что выборка вызов не был завершен, поэтому условное утверждение ложно. Есть ли лучший способ реализовать это? Например, я могу установить время ожидания для количества секунд x, но что, если вызов выборки займет больше времени? Это кажется опасной практикой.

Ниже приведен код для ссылки.

Приложение. js

import React, {Component} from 'react';
import {Route, Switch , NavLink} from 'react-router-dom';

import './App.css'

import InfoContext from '../InfoContext';

import ViewSchedule from '../ViewSchedule /ViewSchedule ';


class App extends Component {

  constructor(props){
    super(props);
    this.state = {
      business: [],
      hours: [],
      fetched: false,
    };
  }


   static contextType = InfoContext;


  checkFetch = () => {
    return new Promise( (resolve,reject) => {
      console.log("waiting...");
      setTimeout(() => {
        if(this.state.fetched === true){
          resolve(true);
        }
      }, 1000);

    });
  }

  componentDidMount() {
    this.fetchDatabase();
}

  fetchDatabase = () => {
    Promise.all([
        fetch(`http://localhost:8000/all`,
        {
            headers: {
                'table':'business'
            }
        }),
        fetch(`http://localhost:8000/all`,
        {
            headers: {
                'table':'hours'
            }
        }),
    ])
        .then(([business, hours]) => {
            console.log('responses received!');

            if (!business.ok)
                return business.json().then(e => Promise.reject(e));
            if (!hours.ok)
                return hours.json().then(e => Promise.reject(e));

            return Promise.all([business.json(), hours.json()]);
        })
        .then( ([business, hours]) => {

            //fetch has been completed and the state has been updated so set "fetched" to true
            this.setState({business, hours, fetched: true});


        })
        .catch(error => {
            console.error({error});
        });
  }

  render(){

    return (
      <InfoContext.Provider value={{businessData: this.state.business,
        dayData: this.state.hours, fetched: this.state.fetched,
        /* METHODS */
        checkFetch: this.checkFetch}}>

        <div className="container">

          <main role="main">

            {/* MAIN TEXT SECTION */}
            <Switch>

              //deleted all the nonessential routes/imports/methods so that this wouldn't be cluttered

              <Route exact path='/view' component={ViewSchedule } />

            </Switch>

          </main>

        </div>
    </InfoContext.Provider>
    );
  }
}

export default App;

ViewSchedule. js

import React from 'react';
import { NavLink } from 'react-router-dom';

import { Container, Row, Col } from 'react-grid-system';

import './ViewSchedule.css';

import {InfoContext } from '../InfoContext';

//require function "call"

const logic = require('../test');



class ViewSchedule extends React.Component{ 

    static contextType = InfoContext;


    async componentDidMount(){

        try{
            let fetched = await this.context.checkFetch();

            // call(this.context.business)

        } catch (err){
            console.log('ERROR in PROMISE: ',err)
        }


    }

    render(){

        return(

        <div className='grid-container'>
            <p>Content removed for testing purposes</p>
        </div>
        );
    }
}


export default ViewSchedule;

InfoContext. js

import React, { createContext, Component} from 'react';

export const InfoContext = createContext({
    businessData: null,
    employeeData: null, dayData: null,
    laborData: null,
    scheduleData: null,
    fetched: null,
    checkFetch: () => {

    },
    updateEmployees: () => {

    },

});

export default InfoContext;

1 Ответ

1 голос
/ 10 февраля 2020

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

Вот простой пример кода, который поможет вам понять этот шаблон:

class ChildComponent extends React.Component {
    onParentFetchFinished(response) {
        // This function is called when parent component finished fetching
    }

    render() {
        return null;
    }
}

class ParentComponent extends React.Component {
    constructor() {
        super();
        this.childComponentRef = React.createRef();
    }

    onClick = () => {
        fetch('someurl').then(response => {
            this.childComponentRef.current.onParentFetchFinished(response);
        });
    }

  render() {
    return (
      <div>
        <button onClick={this.onClick}>Start fetching</button>
        <ChildComponent ref={this.childComponentRef} />
      </div>
    );
  }
}
...