Sennen Randika
Sennen Randika

Reputation: 1636

How to call React Native custom alert as a function?

I'm developing a React Native app. I created my own custom alert as a component using modal. When I use it, I always need to add my alert component in my render() function.

Is there any way to use the custom alert without rendering it inside my render() function?

I mean, I can use Alert in react-native by calling it as Alert.alert(). I want to use my own custom alert also like that.

How can I do that?

Upvotes: 4

Views: 5639

Answers (5)

jnsvu
jnsvu

Reputation: 262

You could do this

class SomeComponent extends Component {
  static myComponentInstance

  constructor(props) {
    super(props)

    this.state = {
      visible: false,
      text: ""
    }

    SomeComponent.myComponentInstance = this
  }

  static show(text) {
    SomeComponent.myComponentInstance._show(text)
  }


  _show(text) {
    this.setState({ visible: true, text })
  }

  render(){
    return (
      <Modal visible={this.state.visible}>
        <Text>{this.state.text}</Text>
      </Modal>
    )
  }
}

const AppRoot = () => (
  <View>
    <Navigator />
    <SomeComponent/>
  </View>
)

And to show it you can do anywhere SomeComponent.show("some text")

Upvotes: 2

Kerem atam
Kerem atam

Reputation: 2777

As i understood, you want your modal to be handled stateless way. Sadly there is no way to do it without Modal being rendered, buuuut you can do it apart from your app render tree by appending a dummy div and manipulate its dom with render inside your function call.

function modalHandler(CustomModal) {
  const div = document.createElement("div");
  this.hide = () => {
    ReactDOM.unmountComponentAtNode(div);
    div.remove();
  };
  this.show = props => {
    document.body.appendChild(div);
    ReactDOM.render(<CustomModal onRequestClose={this.hide} {...props} />, div);
  };

  return {
    show: this.show,
    hide: this.hide,
  };
}

And then create instance for your modal with handler :

const myModal = new modalHandler(CustomModal);

Then you can use your calls anywhere you like without messing your app's render tree:

myModal.show()
myModal.hide()

Example:

const modalStyle = { content: { top: '50%',left: '50%', right: 'auto', bottom: 'auto', marginRight: '-50%', transform: 'translate(-50%, -50%)'}};

const CustomModal = ({ onRequestClose, ...props }) => (
  <ReactModal {...props} isOpen={true} contentLabel="CustomModal" >
    <h1>This modal will close in 3 seconds</h1>
    <button onClick={onRequestClose}>Close</button>
  </ReactModal>
);

// Create Stateless Modal handler from component with HOF
function modalHandler(CustomModal) {
  const div = document.createElement("div");
  this.callOnHide = () => {};
  this.callOnShow = () => {};
  this.hide = () => {
  	this.callOnHide();
    ReactDOM.unmountComponentAtNode(div);
    div.remove();
  };
  this.show = props => {
  	this.callOnShow();
    document.body.appendChild(div);
    ReactDOM.render(<CustomModal onRequestClose={this.hide} {...props} />, div);
  };

  return {
    show: this.show,
    hide: this.hide,
    setOnHideCallback: callback => {
      this.callOnHide = callback;
    },
    setOnShowCallback: callback => {
      this.callOnShow = callback;
    }
  };
}

// Create instance from modal component
const myModal = new modalHandler(CustomModal);

class View extends React.Component {
  openModalHandler = () => {
    myModal.show();

    // auto close in 3 second
    const timer = setTimeout(() => {
      myModal.hide();
    }, 3000);

		// clear the timeout onHide
    myModal.setOnHideCallback(()=>{
    	clearTimeout(timer)
    })
  };

  render() {
    return (
      <div>
        <button onClick={this.openModalHandler}>Open modal</button>
      </div>
    );
  }
}

ReactDOM.render(<View />, document.getElementById("root"));
<script src="https://unpkg.com/[email protected]/dist/react-with-addons.js">
</script>
<script src="https://unpkg.com/[email protected]/dist/react-dom.js">
</script>
<script src="https://unpkg.com/[email protected]/dist/react-modal.min.js">
</script>

<div id="root">
</div>

Upvotes: 0

takesuma
takesuma

Reputation: 151

You can also use this API react-native-popup-dialog to design your alert.

Personnaly I did something like that:

  ...
  <Dialog
  visible={this.props.visible}>
    <DialogContent>
      <View style={ container }>
        <Text style={ title }> { this.props.title } </Text>
        <Text style={ text }> { this.props.text } </Text>
        <View style={ buttonView }>
          <TouchableOpacity style={ button } onPress={ this.props.validationAction }>
            <Text style={ buttonText }>{ this.props.validationText }</Text>
          </TouchableOpacity>
        </View>
      </View>
    </DialogContent>
  </Dialog>
  ...

And the parent:

<Alert
visible={ this.state.visible }
title={ "Alert title" }
text={ "This is an custom alert." }
validationText={ "OK" }
validationAction={ () =>  {
  this.setState({ visible: false });
}} />

I hope it will help.

Upvotes: 0

is343
is343

Reputation: 93

Alert.alert() calls native code. If you want to display your custom alert component, you'll need to add it to your render method. It would be easiest to put it in your root or some other parent component.

Set the component to be displayed conditionally. Create a method to set the condition. You can pass this method down to your child components.

this.alertToggle = (displayAlert) => this.setState({displayAlert});

render(){
  return (
      <Parent>
        {this.state.displayAlert && <CustomAlert/>}
        <Child alertToggle={this.alertToggle}
      </Parent>
    )
}

You can call this.props.alertToggle(true) to display the alert component in the parent.

EDIT: Since you made the component using modal, you could pass the display boolean to the CustomAlert component, and trigger the modal within the component. <CustomAlert displayAlert={this.state.displayAlert} /> The idea of putting the custom alert in the parent is the same.

Upvotes: 0

Junius L
Junius L

Reputation: 16122

Make the method static.

class MyCustomAlert extends React.Component {
  static alert () {
  }
}

usage

import MyCustomAlert from './MyCustomAlert';

MyCustomAlert.alert()

Upvotes: 0

Related Questions