maya dahan
maya dahan

Reputation: 225

How to emit event to app root in react native

I'm trying to implement toast message (notification) on my React Native app. I'm Thinking about implement my Toast component inside app root, and when a button is clicked (somewhere in the app), the app root will know about it and make the toast visible. I don't want to use a library because I have complicated UI for this and I want to include buttons inside the toast.

This is the root component - App.js:

import { Provider } from 'react-redux';

import {Toast} from './src/components/Toast';
import store from './src/store/Store.js';
import AppNavigator from './src/navigation/AppNavigator';
import StatusBar from './src/components/StatusBar';

export default function App(props) {
    return (
        <Provider store = { store }>
          <View style={styles.container}>
            <StatusBar barStyle="default"/>
            <AppNavigator />
            <Toast></Toast>
          </View>
        </Provider>
    );
}

EDIT:

AppNavigator.js:

// this is how I connect each page:
let HomePage = connect(state => mapStateToProps, dispatch => mapDispatchToProps(dispatch))(HomeScreen);
let SearchPage = connect(state => mapStateToProps, dispatch => mapDispatchToProps(dispatch))(SearchScreen);

const HomeStack = createStackNavigator(
    {
        Home: HomePage,
        Search: SearchPage,
    },
    config
);

const mapStateToProps = (state) => {
    return {
        // State
    }
};

const mapDispatchToProps = (dispatch) => {
    return {
        // Actions
    }
};

export default tabNavigator;

Any ideas how can I do it? Thanks.

Upvotes: 1

Views: 2859

Answers (1)

Auticcat
Auticcat

Reputation: 4489

For this, i would suggest to use a component to wrap your application where you have your toast. For example:

App.js

render(){
    return (
      <Provider store = { store }>
          <View style={styles.container}>
              <AppContainer/>
          </View>
    </Provider>
    )
}

Where your AppContainer would have a render method similar to this:

render(){
    return (
        <Frament>
            <StatusBar barStyle="default"/>
            <AppNavigator />
            <Toast></Toast>
        </Fragment>
        )
}

Then (as you are using redux) you can connect your AppContainer. After that, just make this component aware of changes on redux using componentDidUpdate

componentDidUpdate = (prevProps) => {
    if(this.props.redux_toast.visible !== prevProps.redux_toast.visible){
        this.setState({
            toastVisible : this.props.redux_toast.visible,
            toastMessage: this.props.redux_toast.message
        })
    }
}

This is just an example on how it could be done by using redux, I don't know how your toast or redux structure is, but it should be an available solution for your use case.

EDIT.

This is how it should look like:

//CORE
import React from 'react';

//REDUX
import { Provider } from 'react-redux';
import store from './redux/store/store';
import AppContainer from './AppContainer';


export default () => {
  return (
    <Provider store={store}>
        <AppContainer />
    </Provider>
  )
}

AppContainer.js:

import React, { Component } from "react";
import { View, Stylesheet } from "react-native";
import StatusBar from "path/to/StatusBar";
import AppNavigator from "path/to/AppNavigator";
import Toast from "path/to/Toast";
import { connect } from "react-redux";


class AppContainer extends Component {
    constructor(props){
        super(props);
        this.state={
            toastVisible:false,
            toastMessage:""
        }
    }
    componentDidUpdate = (prevProps) => {
        if(this.props.redux_toast.visible !== prevProps.redux_toast.visible){
            this.setState({
                toastVisible : this.props.redux_toast.visible,
                toastMessage: this.props.redux_toast.message
            })
        }
    }


    render(){
        return (
            <View style={styles.container}>
                <StatusBar barStyle="default"/>
                <AppNavigator />
                <Toast visible={this.state.toastVisible}
                    message={this.state.toastMessage}
                />
            </View>
        )
    }
}

const styles = StyleSheet.create({
    container:{
        flex:1
    }
})

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

const mapDispatchToProps = state => ({ ...mapDispatchToProps })

export default connect(mapStateToProps, mapDispatchToProps)(AppContainer)

Rest of the code remains untouched, you need to dispatch an action that changes a props that your appContainer's componentDidUpdate is listening to (in the example i called it redux_toast.visible).

Upvotes: 2

Related Questions