Периодически загружать и отображать сетевые данные с использованием React Native и Redux - PullRequest
0 голосов
/ 27 января 2020

В качестве примера, скажем, мы создаем приложение для биржевой торговли. У нас есть ряд <Stock> компонентов, каждый из которых имеет некоторую опору, например symbol="AAPL".

. У нас также есть центральный магазин Redux с ценами на акции по символам, который периодически обновляется и «выталкивает» любые обновления. к дочерним компонентам. У нас есть StockPriceService, который выполняет выборку, и имеет метод getPrice(symbol), который передается через API-интерфейс контекста следующим образом:

// our App.js render
render() {
  return (
    <StockPriceService.Provider value={stockPriceService}>
      // Rest of view hierarchy
    </StockPriceService.Provider>
  );
}

То, что мы хотим - это несколько функций:

  1. Каждый дочерний компонент <Stock> может отображаться немедленно, с '--' или подобным, пока не будет доступно значение, полученное из сети
  2. Доступность сети восстановленные значения для передачи через действие Redux, которое сохраняет их в магазине (для будущего просмотра в автономном режиме, например, приложение погоды, которое показывает Last Updated: 14 minutes ago)
  3. Получение цен на акции должно указывать на StockPriceService до getPrice(), что если значение не было получено в >= 15 minutes, должен быть выполнен опрос
  4. Если нет значения для запрошенного символа, присутствующего в нашем хранилище Redux, Также следует попытаться провести тот же опрос

Таким образом, метод визуализации <Stock> может выглядеть следующим образом:

return (
  <Text>{this.props.symbol}: ${this.context.getPrice(this.props.symbol)}</Text>
);

Моя проблема / вопрос: This "работает ", в этом getPrice() действительно может проверить местный Redux store, чтобы увидеть, что доступно, и вернуть значение, если оно есть. Но когда он не и запускает фоновую загрузку, как компоненту <Stock> легко сигнализировать о необходимости повторного рендеринга?

Создание части price состояние для компонента <Stock> означает, что компонент теперь может автоматически повторно отображаться, но как должно происходить обновление состояния после завершения загрузки?

Если <Stock> Компонент должен был получить свою цену акций непосредственно из магазина Redux, повторный рендеринг работал бы должным образом после действия Redux, обновляющего магазин Redux, но, обойдя StockPriceSymbol, у него не было бы возможности проверить, новый ли опрос требуется или обрабатывать соответствующие бизнес-логики c для извлечения / сохранения новых / несуществующих значений.

1 Ответ

0 голосов
/ 27 января 2020

следующее должно удовлетворить все ваши требования. Я не использую контекстный API, просто React + Redux. connect и mapStateToProps позаботятся о автоматическом распространении цен и временных меток для компонента Stock. Каждый установленный компонент Stock будет обновляться каждую минуту. Это означает, что «обновленные x минут go» будут отрисованы заново, и если прошло 15 минут, он снова получит цену.

import { getPrice as getStockPrice }  from './StockPriceService';

// Assumed state and reducer structure:
/*
state = {
    stock: {
        AAPL: {
            price: 318.31,
            lastUpdated: 1580114309023
        },
        GOOGL: {
            price: 1466.17,
            lastUpdated: 1580114309045
        }
    }
}
*/

// Thunk action
const fetchPrice = (symbol) => {
    return async function(dispatch, getState) {
        dispatch(fetchPriceRequest(symbol));
        try {
            const { price } = await getStockPrice(symbol);
            const lastUpdated = Date.now();
            // save price and timestamp through reducer
            dispatch(fetchPriceSuccess(symbol, price, lastUpdated));
        } catch (error) {
            dispatch(fetchPriceFailure(symbol));
        }
    };
};

// Selectors
const getPrice = (state, symbol) => (state.stock[symbol] && state.stock[symbol].price) || '--';
const getLastUpdated = (state, symbol) => (state.stock[symbol] && state.stock[symbol].lastUpdated) || 'never';

// Creating a connected Stock component
const Stock = ({ symbol, price, lastUpdated, fetchPrice }) => {
    const [updatedWhen, setUpdatedWhen] = useState('never');
    const [intervalID, setIntervalID] = useState(null);

    useEffect(() => {
        // On first render during entire app runtime, fetch price immediately
        if (price === '--' || lastUpdated === 'never') {
            fetchPrice(symbol);            
        }

        // Check every minute for updates
        const id = setInterval(() => {
            const now = Date.now();

            // TODO: some nicer date formatting here, I left this part out.
            setUpdatedWhen(now - lastUpdated);

            const isPriceOutdated = lastUpdated + (15 * 60 * 1000) <= now;
            if (price === '--' || lastUpdated === 'never' || isPriceOutdated) {
                fetchPrice(symbol);
            }
        }, 60 * 1000);
        setIntervalID(id);

        return function cleanup() {
            clearInterval(intervalID);
        };
    }, []);

    return (
        <Text>{symbol}: {price}} (last updated: {lastUpdated} {updatedWhen})</Text>
    );
};

const mapStateToProps = (state, ownProps) => ({
    const { symbol } = ownProps;
    return {
        price: getPrice(state, symbol),
        lastUpdated: getLastUpdated(state, symbol);
    };
})

const mapDispatchToProps = {
    fetchPrice
};


// Use this connected component in your app
const ConnectedStock = connect(mapStateToProps, mapDispatchToprops)(Stock);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...