구성 요소에 렌더링시기를 알리기 위해 전역 상태 변수를 사용하도록 설정했습니다. Redux는 많은 구성 요소가 서로 대화하는 시나리오에서 더 좋으며 때로는 사용한다고 언급했습니다. Redux를 사용하여 답을 그려 보겠습니다.
API 호출을 상위 컨테이너 ()로 이동해야합니다 Component A
. API 호출이 완료된 후에 만 손자를 렌더링하려면 손자 자체에 해당 API 호출을 유지할 수 없습니다. 아직 존재하지 않는 구성 요소에서 API 호출을 어떻게 만들 수 있습니까?
모든 API 호출이 완료되면 조치를 사용하여 많은 데이터 오브젝트를 포함하는 전역 상태 변수를 업데이트 할 수 있습니다. 데이터가 수신 될 때마다 (또는 오류가 발견 될 때마다) 데이터 오브젝트가 완전히 채워 졌는지 확인하기 위해 조치를 전달할 수 있습니다. 완전히 채워지면 loading
변수를로 업데이트 false
하고 조건부로 Grid
구성 요소를 렌더링 할 수 있습니다.
예를 들어 :
// Component A
import { acceptData, catchError } from '../actions'
class ComponentA extends React.Component{
componentDidMount () {
fetch('yoururl.com/data')
.then( response => response.json() )
// send your data to the global state data array
.then( data => this.props.acceptData(data, grandChildNumber) )
.catch( error => this.props.catchError(error, grandChildNumber) )
// make all your fetch calls here
}
// Conditionally render your Loading or Grid based on the global state variable 'loading'
render() {
return (
{ this.props.loading && <Loading /> }
{ !this.props.loading && <Grid /> }
)
}
}
const mapStateToProps = state => ({ loading: state.loading })
const mapDispatchToProps = dispatch => ({
acceptData: data => dispatch( acceptData( data, number ) )
catchError: error=> dispatch( catchError( error, number) )
})
// Grid - not much going on here...
render () {
return (
<div className="Grid">
<GrandChild1 number={1} />
<GrandChild2 number={2} />
<GrandChild3 number={3} />
...
// Or render the granchildren from an array with a .map, or something similar
</div>
)
}
// Grandchild
// Conditionally render either an error or your data, depending on what came back from fetch
render () {
return (
{ !this.props.data[this.props.number].error && <Your Content Here /> }
{ this.props.data[this.props.number].error && <Your Error Here /> }
)
}
const mapStateToProps = state => ({ data: state.data })
감속기는 전역 상태 객체를 유지하여 모든 준비가 완료되었는지 여부를 알려줍니다.
// reducers.js
const initialState = {
data: [{},{},{},{}...], // 9 empty objects
loading: true
}
const reducers = (state = initialState, action) {
switch(action.type){
case RECIEVE_SOME_DATA:
return {
...state,
data: action.data
}
case RECIEVE_ERROR:
return {
...state,
data: action.data
}
case STOP_LOADING:
return {
...state,
loading: false
}
}
}
당신의 행동에서 :
export const acceptData = (data, number) => {
// First revise your data array to have the new data in the right place
const updatedData = data
updatedData[number] = data
// Now check to see if all your data objects are populated
// and update your loading state:
dispatch( checkAllData() )
return {
type: RECIEVE_SOME_DATA,
data: updatedData,
}
}
// error checking - because you want your stuff to render even if one of your api calls
// catches an error
export const catchError(error, number) {
// First revise your data array to have the error in the right place
const updatedData = data
updatedData[number].error = error
// Now check to see if all your data objects are populated
// and update your loading state:
dispatch( checkAllData() )
return {
type: RECIEVE_ERROR,
data: updatedData,
}
}
export const checkAllData() {
// Check that every data object has something in it
if ( // fancy footwork to check each object in the data array and see if its empty or not
store.getState().data.every( dataSet =>
Object.entries(dataSet).length === 0 && dataSet.constructor === Object ) ) {
return {
type: STOP_LOADING
}
}
}
곁에
API 호출이 각 손자 내부에 존재하지만 모든 API 호출이 완료 될 때까지 전체 손자 그리드가 렌더링되지 않는다는 아이디어와 실제로 결혼하면 완전히 다른 솔루션을 사용해야합니다. 이 경우 손자를 처음부터 렌더링하여 호출해야하지만 display: none
전역 클래스 변수 loading
가 false로 표시된 후에 만 변경되는 css 클래스가 있어야합니다 . 이것은 또한 가능하지만, React의 관점 이외에도 가능합니다.