Обзор:
Я использую 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;