Лучший способ показывать всплывающие уведомления и навигацию в React Native
Это очень распространенная функция — показывать всплывающие уведомления в приложении, чтобы информировать пользователя об определенных событиях. Например, для отображения всплывающего уведомления о потере подключения к Интернету «вы вышли из сети».
Пример того, как показать всплывающее уведомление, взятое непосредственно из документов react-native-easy-toast, выглядит следующим образом.
render() {
return (
<View style={styles.container}>
<TouchableHighlight
style={{padding: 10}}
onPress={()=>{
this.refs.toast.show('hello world!');
}}>
<Text>Press me</Text>
</TouchableHighlight>
<Toast ref="toast"/>
</View>
)
}
Но что, если мы
Не хотите использовать компонент Toast для каждого компонента
Не хотите делать ссылки для каждого компонента Toast
Хотите показать тост от redux-thunk или самой redux-saga после определенного побочного эффекта
Эти проблемы можно решить, добавив один компонент Toast в корневой компонент приложения.
Если вы используете редукцию, пример будет следующим
class Root extends React.Component {
...
render() {
return (
<Provider>
<View>
<ApplicationContainer />
<Toast ref="toast" />
</View>
</Provider>
);
}
}
Но как сделать тост доступным для компонентов, которые его требуют??????
Мы можем
Передайте ссылку всем компонентам через контекстный API реакции
Сохраните ссылку в переменной и сделайте ее доступной для всех наших компонентов через экспорт.
Есть ли лучший способ сделать это ?? Должна же быть, да??
Enter — эмиттеры событий в стиле узла спешат на помощь
Существует множество эмиттеров событий, которые можно использовать для генерации, прослушивания и выполнения действий с событиями, например, Mitt (функциональный эмиттер событий Tiny 200b / pub-sub).
Использование эмиттеров событий для отображения всплывающих уведомлений
Вышеупомянутые проблемы можно решить, если связать событие с всплывающим уведомлением и продолжать генерировать всплывающее уведомление всякий раз, когда нам нужно показать всплывающее уведомление.
Теперь приведенный выше код можно изменить как
const emitter = mitt()
class Root extends React.Component {
...
showToast = params => {
if (this.toast.current) {
this.toast.current.show(params.message, params.duration);
}
};
componentDidMount() {
emitter.on("showToast", this.showToast);
}
componentWillUnmount() {
emitter.off("showToast", this.showToast);
}
render() {
return (
<Provider>
<View>
<ApplicationContainer />
<Toast ref="toast" />
</View>
</Provider>
);
}
}
// Теперь из любого компонента, если мы хотим показать тост
class SubscribingComponent {
render() {
return (
<View>
<TouchableHighlight
onPress={() => {
emitter.emit("showToast", {
message: "Hello World",
duration: 1000
});
}}
>
<Text>Press me</Text>
</TouchableHighlight>
</View>
);
}
}
Это кажется намного лучшим, лаконичным и красивым способом обработки тостов.
Единственный недостаток, который я предвижу, это то, что мы не можем стилизовать тост для определенных сценариев. Если стилизация для вас не проблема, то, возможно, вы можете попробовать показывать всплывающие уведомления с помощью эмиттеров событий.
Использование эмиттеров событий для навигации
Излучатели событий снова можно использовать, в частности, в React Native в определенных сценариях, когда нам нужно перейти на какой-то другой экран после завершения побочного эффекта (действия). Несмотря на то, что react-navigation предоставляет способ доступа к навигации за пределами вашего компонента, навигация вне компонента, особенно из redux-thunk или redux-saga, кажется немного странной. Небольшой пример будет следующим
// в вашем преемнике или саге
function* someSaga() {
// this saga responds to the action
// api call
yield call(apiCall);
// on success emit navigate event
emitter.emit("navigateEvent", {
routeName: "route",
params: { title: "hello" }
});
}
class SampleComponent {
componentDidMount() {
emitter.on("navigateEvent", this.redirectToSomePage);
}
componentWillUnmount() {
emitter.off("navigateEvent",this.redirectToSomePage);
}
redirectToSomePage = route => {
navigation.navigate(route.routeName, route.params);
};
render() {
return (
<TouchableOpacity onPress={DispatchSomeAction}>
<Text> Press me</Text>
</TouchableOpacity>
);
}
}
Надеюсь, это поможет… ура !!!!