React / Redux: подождите, пока редуктор получит реквизит - PullRequest
1 голос
/ 11 марта 2019

У меня есть следующий компонент, который я использую для навигации:

import React, { Component } from "react";
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';

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

    const noTankAvailable = this.props.tank.tankData.noAssignedTank;
    console.log("noTankAvailable", noTankAvailable);

    if (noTankAvailable === true || noTankAvailable === undefined) {
      this.tabs = [
        { label: "Registration", icon: faSimCard, url: "registration" }
      ];
    } else {
      this.tabs = [
        { label: "Status", icon: faChartBar, url: "status" },
        { label: "History", icon: faHistory, url: "history" },
        { label: "Properties", icon: faSlidersH, url: "properties" }
      ];
    }
    ...
  }
  ...
  render() {
    const { location, match } = this.props;
    const { pathname } = location;
    return (
      <div>
        <Tabs
          className="tabBar"
          contentContainerStyle={tabBarStyles.content}
          inkBarStyle={tabBarStyles.ink}
          tabItemContainerStyle={tabBarStyles.tabs}
          value={pathname}
        >
          {this.renderTabs(match)}
        </Tabs>
      </div>
    );
  }
}

const mapStateToProps = state => ({
  ...state
});

export default connect(mapStateToProps)(TabBar);

Это мой редуктор:

import {
  TANK_REQUEST,
  TANK_FAILURE,
  TANK_SUCCESS,
} from '../actions/tankActions';

const testState = {
  isLoading: false,
  currentTank: "",
  tankData: {}
};

export default (state = testState, action) => {
  switch (action.type) {
    case TANK_REQUEST:
      return Object.assign({}, state, { isLoading: true });
    case TANK_SUCCESS:
      if (action.tankData.length > 0) {
        const currentTank = action.tankData[0];
        const tankData = Object.assign({}, state.tankData, { [currentTank._id]: currentTank, isLoading: false });
        return Object.assign({}, state, { currentTank: currentTank._id, tankData });
      } else {
        const tankData = Object.assign({}, state.tankData, { noAssignedTank: true });
        return Object.assign({}, state, { tankData });
      }
    case TANK_FAILURE:
      return Object.assign({}, state, { currentTank: action.id, isLoading: false, error: action.err });
    default:
      return state
  }
}

Дается следующий сценарий: Когда пользователь входит в систему, он получает API для получения (воды) резервуаров. Если у пользователя нет назначенного резервуара, приложение должно перенаправить в представление регистрации, а в навигации должна отображаться только «регистрация».

enter image description here Так что я получаю через действие. В своем редукторе я проверяю, получил ли я данные, а если нет, то добавлю noAssignedTank: true к своему состоянию. Теперь я хочу проверить в своем компоненте TabBar, верно ли это или нет, и скрыть / показать навигационные ссылки в зависимости от этого.

Моя проблема заключается в том, что мне нужно подождать, пока редуктор TANK_FETCHING_SUCCESS не будет разрешен, чтобы проверить, является ли noAssignedTank истинным.

enter image description here

Вы можете видеть, что первый вывод консоли - мой console.log("noTankAvailable", noTankAvailable);. Так что мой оператор if / else не работает, потому что сначала он undefined, прежде чем он получает значение.

1 Ответ

2 голосов
/ 11 марта 2019

Вы должны сделать this.tabs состоянием вашего компонента и обновлять его во время методов жизненного цикла вашего компонента.

Получение tankData было обеспечено дополнительными тестами (props.tank && props.tank.tankData).

Начальное состояние инициализируется в конструкторе с помощью реквизита.

Ссылка на предыдущий резервуар также сохраняется в состоянии (prevTanData) для сравнения, когда изменится реквизит (когда будет обновлено асинхронное значение в хранилище, подключенный компонент будет уведомлен при помощи приставки, и последует вызов getDerivedStateFromProps. ).

Если prevTankData совпадает с nextProps.tank.tankData, тогда мы возвращаем нуль, чтобы сообщить React, что состояние не нужно менять.

Обратите внимание, что для версии React <16 вам придется использовать метод экземпляра <code>componentWillReceiveProps вместо статического getDerivedStateFromProps.

    class TabBar extends Component {
        constructor(props) {
            super(props);
            this.state = {
               tabs: TabBar.computeTabsFromProps(props),
               prevTankData: props.tank && props.tank.tankData,
            };
        };

        static computeTabsFromProps(props) {
            const noTankAvailable = props.tank &&
                                    props.tank.tankData &&
                                    props.tank.tankData.noAssignedTank;
            console.log("noTankAvailable", noTankAvailable);

            if (noTankAvailable === true || noTankAvailable === undefined) {
                return [
                    {
                        label: "Registration",
                        icon: faSimCard,
                        url: "registration"
                    }
                ];
            } else {
                return [
                    { label: "Status", icon: faChartBar, url: "status" },
                    { label: "History", icon: faHistory, url: "history" },
                    { label: "Properties", icon: faSlidersH, url: "properties" }
                ];
            }
        }
        static getDerivedStateFromProps(nextProps, prevState) {
            if ((nextProps.tank && nextProps.tank.tankData) !== prevState.prevTankData) {
                return {
                    prevTankData: nextProps.tank && nextProps.tank.tankData,
                    tabs: TabBar.computeTabsFromProps(nextProps),
                }
            }
            return null;
        }
        render() {
            ...
        }
    }
...