Как использовать Redux в реагирующем для отправки действий по изменению подключения NetInfo?

1

Я хотел бы иметь возможность "постоянно" отслеживать подключение к устройству в своем адаптивном приложении.

Я уже с успехом использую redux-thunk и redux.

На самом деле я могу это сделать

import { NetInfo } from 'react-native';

import {
    CONNECTION_CHECKING,
    CONNECTION_AVAILABLE,
    CONNECTION_UNAVAILABLE, 
} from './types';


export const connectionChecking = () => {
    return (dispatch) => {

        dispatch ({
            type: CONNECTION_CHECKING
        });

        NetInfo.getConnectionInfo()
            .then((connectionInfo) => {

                console.log('Connection info: ', connectionInfo);
                switch (connectionInfo.type) {
                    case 'cellular':
                        dispatch ({
                            type: CONNECTION_AVAILABLE,
                            payload: connectionInfo.type
                        });
                        break;
                    case 'wifi':
                        dispatch ({
                            type: CONNECTION_AVAILABLE,
                            payload: connectionInfo.type
                        });
                        break;
                    default:
                        dispatch ({
                            type: CONNECTION_UNAVAILABLE,
                        });
                }
            })
            .catch((error) => console.warn(error));

    };
};

Но я не знаю, как отправлять новые действия при изменении соединения.

Из ответного документа я вижу следующее:

NetInfo.addEventListener(
  'connectionChange',
  handleConnectivityChange
);

Но... как отправить действие внутри прослушивателя событий?

Я попытался добавить это в тот же файл действия

NetInfo.addEventListener(
    'connectionChange', (connectionInfo)  => {
        return (dispatch) => {

            console.log('Connection info changed ', connectionInfo);
            switch (connectionInfo.type) {
                case 'cellular':
                case 'wifi':
                    dispatch ({
                        type: CONNECTION_AVAILABLE,
                        payload: connectionInfo.type
                    });
                    break;
                default:
                    dispatch ({
                        type: CONNECTION_UNAVAILABLE,
                    });
            }

        };
    }
);

У меня нет никаких результатов, нет console.log, и поэтому я думаю, что это неправильный путь

Теги:
react-native
redux
redux-thunk

1 ответ

3
Лучший ответ

Вам просто нужно настроить прослушиватель событий где-нибудь с доступом к функции dispatch.

Непосредственно из компонента

Проще всего сделать (разрешая чистую отмену подписки) - установить их в свой самый верхний подключенный компонент:

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

    // Dispatch an action from your event handler (and do whatever else)
    this._handleConnectionChange = (connectionInfo) => props.dispatch({ 
      type: 'CONNECTION_CHANGE', 
      connectionInfo
    });

    NetInfo.addEventListener('connectionChange', this._handleConnectionChange);
  }

  componentWillUnmount() {
    NetInfo.removeEventListener('connectionChange', this._handleConnectionChange);
  }
}

export default connect()(MyApp); // MyApp must be connected

Небольшая абстракция - добавление слушателя в Thunk

Лично мне нравится обертывать подобные вещи в thunk, чтобы избежать обработки слушателем загромождения моих компонентов. Важным моментом здесь является то, что штыри, такие как связанные компоненты, имеют доступ к dispatch, поэтому, определяя слушателя во внутренней части thunk, мы можем отправлять действия (или больше thunks) в ответ на изменения.

// connectionActions.js

let handleConnectionChange;

export function registerListeners() {
  return (dispatch) => {
    handleConnectionChange = (connectionInfo) => {
      dispatch(connectionChanged(connectionInfo));
    }
    NetInfo.addEventListener('connectionChange', handleConnectionChange);
  }
}

export function unregisterListeners() {
  return (dispatch) => {
    handleConnectionChange && NetInfo.removeEventListener('connectionChange', handleConnectionChange);
  }
}

function connectionChanged(connectionInfo) {
  return (dispatch) => {
    switch (connectionInfo.type) {
      case 'cellular':
        dispatch({
          type: CONNECTION_AVAILABLE,
          payload: connectionInfo.type
        });
        break;
      // ...Other cases
    }
  }
}

И тогда вы можете отправлять registerListeners() и unregisterListeners() из MyApp а не определять подробности слушателей там:

// app.js
// ...other imports
import * as connectionActions from './connectionActions'

class MyApp extends Component {
  constructor(props) {
    super(props);
    // Dispatch your thunk to take care of the registration
    props.dispatch(connectionActions.registerListeners());
  }

  componentWillUnmount() {
    this.props.dispatch(connectionActions.unregisterListeners());
  }
}

export default connect()(MyApp)

Немного больше абстракции - компонент более высокого порядка для прослушивания

В приложениях, где у меня есть несколько возможных компонентов верхнего уровня (например, разные варианты сборки с разными домашними страницами или экран входа в систему, который не является частью основного навигатора), мне нравится использовать этот шаблон и обернуть его в компонент более высокого порядка:

// hoc/withNetListeners.js

export default function withNetListeners(SourceComponent): {
  class HOC extends React.Component {
    constructor(props) {
      super(props);
      props.dispatch(connectionActions.registerListeners());
    }

    componentWillUnmount() {
      this.props.dispatch(connectionActions.unregisterListeners());
    }

    render() {
      return <SourceComponent {...this.props} />;
    }
  }
  return hoistStatics(HOC, SourceComponent); // Package hoist-non-react-statics
}

И затем в зависимости от того, какой компонент действуют как ваш корень (ы):

// app.js
class MyApp extends Component {
  // ... Just your UI, no listeners ...
}

// Inject the listeners with a HOC. Make you 'connect' last, because 
// 'withNetListeners' needs to be given access to 'dispatch'.
export default connect()(withNetListeners(MyApp))
  • 0
    Спасибо за очень качественный ответ. Я прошу вас расширить версию "Маленькая абстракция". Я не могу понять в этом сценарии, ГДЕ и КАК я могу вызвать NetInfo.addEventListener. Моя цель состоит в том, чтобы в файле «connectionActions.js» было действие, которое будет вызываться после монтирования основного компонента (this.props.callNetInfoRegistration .... () или аналогичного), чтобы я мог обрабатывать изменения подключения при изменении состояния, где бы я ни находился нужно
  • 1
    Нет проблем - я добавил некоторые пояснения в этот раздел. Это помогает? (Еще одно обновление - только что понял, что я забыл вызов NetInfo.addEventListener ! NetInfo.addEventListener может быть яснее ..)
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню