Dawn17
Dawn17

Reputation: 8297

Switching between two components in React

  rotateRender() {

    if(false) {

      return(
        <TimerPage></TimerPage>
      );


    } else {


      return(
        <RepoPage></RepoPage>
      );

    }
  }

I have two components called TimerPage and RepoPage. I created a simple conditional render function as above, but cannot come up with a condition to make it render iteratively after a certain amount of time.

For example, I first want to render RepoPage and switch to TimerPage after 5 minutes and then stay in TimerPage for 15 mins before I switch again to the RepoPage.

Any way to do this?

Upvotes: 2

Views: 3093

Answers (3)

Lucaci Sergiu
Lucaci Sergiu

Reputation: 574

Might not be that elegant, but this works

Actually I was thinking that this block might be more elegant than the first one

const FIRST_PAGE = '5_SECONDS';
const SECOND_PAGE = '15_SECONDS';

const FirstComponent = () => (
  <div>5 SECONDS</div>
);

const SecondComponent = () => (
  <div>15 SECONDS</div>
);

class App extends Component {
  state = {
    currentPage: FIRST_PAGE
  };

  componentDidUpdate() {
    const {currentPage} = this.state;
    const isFirst = currentPage === FIRST_PAGE;

    if (isFirst) {
      this._showSecondPageDelayed();
    } else {
      this._showFirstPageDelayed();
    }
  }

  componentDidMount() {
    this._showSecondPageDelayed();
  };

  _showSecondPageDelayed = () => setTimeout(() => {this.setState({currentPage: SECOND_PAGE})}, 5000);

  _showFirstPageDelayed = () => setTimeout(() => {this.setState({currentPage: FIRST_PAGE})}, 15000);

  render() {
    const {currentPage} = this.state;
    const isFirst = currentPage === FIRST_PAGE;
    const ComponentToRender =  isFirst ? FirstComponent : SecondComponent;

    return <ComponentToRender/>;
  }
}

Upvotes: 1

MEnf
MEnf

Reputation: 1512

As stated in the comment section, you can create a higher order component that will cycle through your components based on the state of that component. Use setTimeout to handle the timer logic for the component.

state = {
  timer: true
}

componentDidMount = () => {
  setInterval(
    () => {
    this.setState({ timer: !this.state.timer })
  }, 30000)
}

render(){
  const {timer} = this.state
  if(timer){
    return <TimerPage />
  } else {
    return <RepoPage />
  }
}

Edit

Changed setTimeout to setInterval so that it will loop every 5 minutes instead of just calling setState once

Upvotes: 1

Steven Scaffidi
Steven Scaffidi

Reputation: 2307

You could use the new context API to achieve this. The benefit is now I have a configurable, reusable provider to play with throughout my application. Here is a quick demo: https://codesandbox.io/s/k2vvy54r8o

import React, { Component, createContext } from "react";
import { render } from "react-dom";

const ThemeContext = createContext({ alternativeTheme: false });

class ThemeWrapper extends Component {
  state = {
    alternativeTheme: false
  };

  themeInterval = null;

  componentDidMount() {
    this.themeInterval = setInterval(
      () =>
        this.setState(({ alternativeTheme }) => ({
          alternativeTheme: !alternativeTheme
        })),
      this.props.intervalLength
    );
  }

  componentWillUnmount() {
    if (this.themeInterval) {
      clearInterval(this.themeInterval);
    }
  }

  render() {
    return (
      <ThemeContext.Provider value={this.state}>
        {this.props.children}
      </ThemeContext.Provider>
    );
  }
}

const App = () => (
  <ThemeWrapper intervalLength={2000}>
    <ThemeContext.Consumer>
      {({ alternativeTheme }) =>
        alternativeTheme ? <p>Alternative Theme</p> : <p>Common Theme</p>
      }
    </ThemeContext.Consumer>
  </ThemeWrapper>
);

render(<App />, document.getElementById("root"));

Whatever you do make sure on componentWillUnmount to clear your interval or timeout to avoid a memory leak.

Upvotes: 0

Related Questions