Search code examples
reactjsreduxredux-sagareselect

React child component does not receive props on first load


I am fetching data in parent 'wrapper' component and pass it down to two child components. One child component receives it well, another does not.

In container:

const mapStateToProps = createStructuredSelector({
  visitedCountriesList: getVisitedCountriesList(),
  visitedCountriesPolygons: getVisitedCountriesPolygons()
});

export function mapDispatchToProps(dispatch) {
  return {
    loadVisitedCountries: () => {
      dispatch(loadVisitedCountriesRequest())
    },
  };
}

in redux-saga I fetch data from API and store them:

function mapPageReducer(state = initialState, action) {
   switch (action.type) {
     case FETCH_VISITED_COUNTRIES_SUCCESS:
       return state
         .setIn(['visitedCountriesPolygons', 'features'], action.polygons)
 }

Selectors:

const getVisitedCountriesList = () => createSelector(
  getMapPage,
  (mapState) => {
    let countriesList = mapState.getIn(['visitedCountriesPolygons', 'features']).map(c => {
      return {
        alpha3: c.id,
        name: c.properties.name
      }
    });
    return countriesList;
  }
)

const getVisitedCountriesPolygons = () => createSelector(
  getMapPage,
  (mapState) => mapState.get('visitedCountriesPolygons')
)

in a wrapper component I render two components, triggering data fetch and passing props down to child components (visitedCountriesPolygons and visitedCountriesList):

class MapView extends React.Component {
  constructor(props) {
    super(props)
    this.props.loadVisitedCountries();
  }

  render() {
    return (
      <div>
        <Map visitedCountriesPolygons={this.props.visitedCountriesPolygons} />
        <MapActionsTab visitedCountriesList={this.props.visitedCountriesList} />
      </div>
    );
  }
}

Then, in first child component Map I receive props well and can build a map:

componentDidMount() {
    this.map.on('load', () => {
      this.drawVisitedPolygons(this.props.visitedCountriesPolygons);
    });
};

But in the second component MapActionsTab props are not received at initial render, but only after any update:

class MapActionsTab extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    let countriesList = this.props.visitedCountriesList.map(country => {
      return <li key={country.alpha3}>{country.name}</li>;
    }) || '';

    return (
      <Wrapper>
          <div>{countriesList}</div>
      </Wrapper>
    );
  }
}

UPD: Saga to fetch data form API:

export function* fetchVisitedCountries() {
  const countries = yield request
    .get('http://...')
    .query()
    .then((res, err) => {
      return res.body;
  });
  let polygons = [];
  yield countries.map(c => {
    request
      .get(`https://.../${c.toUpperCase()}.geo.json`)
      .then((res, err) => {
        polygons.push(res.body.features[0]);
      })
  });
  yield put(fetchVisitedCountriesSuccess(polygons));
}

and a simple piece of reducer to store data:

case FETCH_VISITED_COUNTRIES_SUCCESS:
       return state
         .setIn(['visitedCountriesPolygons', 'features'], action.polygons)

Why is it different and how to solve it, please?

thanks, Roman


Solution

  • Apparently, this works correct and it was just a minor issue in another place (not pasted here and not errors reported). After thorough clean up and refactoring it worked as expected.

    Conclusion: always keep your code clean, use linter and follow best practices :)