1

I'm new to React, sorry if this is too basic.

I am trying to render a simple animation when <Link> is clicked in React.

I have Coffees.jsx:

import Brewing from './Brewing.jsx';

  handleClick() {
    return (<Brewing/>)
  }

  render(){
    return (
       <div>
        <div>
          <Link onClick={this.handleClick} to="/brewing">Coffee</Link>
        </div>
      </div>
    );       
  }
}

export default Menus;

and Brewing.jsx:

import './css/mug.css'

class Brewing extends Component {
    constructor (props) {
    super(props);
  };
    render() {
        return (
            <div>
              <div className="cup">
                <div className="coffee"></div>
              </div>
              <div className="smoke"></div>
            </div>
        );
    }
}

export default Brewing; 

The above is not working. It only works if I inject the animation:

<div className="cup">
  <div className="coffee"></div>
</div>
<div className="smoke"></div>  

directly into Coffees.jxs, like so:

 render(){
    return (
       <div>
        <div>
         <div className="cup">
          <div className="coffee"></div>
         </div>
         <div className="smoke"></div>  
          <Link to="/brewing"></Link>
        </div>
      </div>
    );       
  }

But this is not desired...How do I render this animation at onClick?

EDIT:

App.jsx

class App extends Component {
  constructor() {
    super();
    this.state = {
      users: [],
      isAuthenticated: false,
      messageName: null,
      messageType: null,
      select:'',
      email: '',
      id: '',
      username: '',
      active: '',
      admin: '',  
      //task:''
    };
    this.logoutUser = this.logoutUser.bind(this);
    this.loginUser = this.loginUser.bind(this);
    this.createMessage = this.createMessage.bind(this);
    this.removeMessage = this.removeMessage.bind(this);
    this.userId = this.userId.bind(this);
  };
  componentWillMount() {
    if (window.localStorage.getItem('authToken')) {
      this.setState({ isAuthenticated: true });
    };
  };
  componentDidMount() {
    this.getUsers();
    this.userId();
  };
  getUsers() {
    axios.get(`${process.env.REACT_APP_WEB_SERVICE_URL}/users`)
    .then((res) => { this.setState({ users: res.data.data.users }); })
    .catch((err) => { });
  };
  logoutUser() {
    window.localStorage.clear();
    this.setState({ isAuthenticated: false });
  };
  loginUser(token) {
    window.localStorage.setItem('authToken', token);
    this.setState({ isAuthenticated: true });
    this.getUsers();
    this.createMessage('Welcome', 'success');
  };
  userId(event) {
    const options = {
      url: `${process.env.REACT_APP_WEB_SERVICE_URL}/auth/status`,
      method: 'get',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${window.localStorage.authToken}`
      }
    };
    return axios(options)
    .then((res) => { 
      console.log(res.data.data) 
      this.setState({
        select: res.data.data.select,
        email: res.data.data.email,
        id: res.data.data.id,
        username: res.data.data.username,
        active: String(res.data.data.active),
        admin: String(res.data.data.admin),
      })
    })
    .catch((error) => { console.log(error); });
  };
  createMessage(name='Sanity Check', type='success') {
    this.setState({
      messageName: name,
      messageType: type
    });
    setTimeout(() => {
      this.removeMessage();
    }, 3000);
  };
  removeMessage() {
    this.setState({
      messageName: null,
      messageType: null
    });
  };
  render() {
    return (
      <div>
        <NavBar
          title={this.state.title}
          isAuthenticated={this.state.isAuthenticated}
        />
        <section className="section">
          <div className="container">
            {this.state.messageName && this.state.messageType &&
              <Message
                messageName={this.state.messageName}
                messageType={this.state.messageType}
                removeMessage={this.removeMessage} 
              />
            }
            <div className="columns">
              <div className="column is-half">
                <br/>
                <Switch>
                  <Route exact path='/about' component={About}/>
                  <Route exact path='/register' render={() => (
                    <Form
                      formType={'Register'}
                      isAuthenticated={this.state.isAuthenticated}
                      loginUser={this.loginUser}
                      createMessage={this.createMessage}
                      userId={this.state.id} 
                    />
                  )} />
                  <Route exact path='/login' render={() => (
                    <Form
                      formType={'Login'}
                      isAuthenticated={this.state.isAuthenticated}
                      loginUser={this.loginUser}
                      createMessage={this.createMessage}
                      userId={this.state.id} 
                    />
                  )} />
                  <Route exact path='/logout' render={() => (
                    <Logout
                      logoutUser={this.logoutUser}
                      isAuthenticated={this.state.isAuthenticated}
                    />
                  )} />
                  <Route exact path='/status' render={() => (
                    <UserStatus
                      isAuthenticated={this.state.isAuthenticated}
                    />
                  )} />
                  <Route exact path='/seeds' render={() => (
                    <Seeds
                      isAuthenticated={this.state.isAuthenticated}
                      userId={this.state.id}
                    />
                  )} />
                  <Route exact path='/menus' render={() => (
                    <Menus
                      isAuthenticated={this.state.isAuthenticated}
                      userId={this.state.id}
                    />
                  )} />
                  <Route exact path='/coffee' render={() => (
                    <Coffees
                      isAuthenticated={this.state.isAuthenticated}
                      userId={this.state.select}
                    />
                  )} />
                </Switch>
              </div>
            </div>
          </div>
        </section>
      </div>
    )
  }
};

export default App;
9
  • Do you have Route for brewing? Commented Aug 12, 2019 at 1:27
  • Can you post your Routes? Commented Aug 12, 2019 at 1:35
  • Don’t have any, should I? Commented Aug 12, 2019 at 1:36
  • Yes. If you are using Link then you should have Route to handle those Link clicks. Can you tell me what needs to be happen when someone clicks any Link. I just understood that when someone clicks Link animation should start, but what next? Commented Aug 12, 2019 at 2:01
  • Next a redirecion will happen to another route Commented Aug 12, 2019 at 2:03

2 Answers 2

1

When you click any Link it will not wait on that component to execute any event, it will simply redirect to given path (to="/coffees"), so you need Route to handle this path.

Instead of Link we can use a button or simply a div (you can style it so that it look like link) and write onClick handler on that. In that handler we need to add a setTimeout with the timeout of actual animation.

Now when setTimeout executes, we can set a variable in state which will help us to redirect to desired component.

Your menu component should be,

class Menu extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      isLoading: false,
      redirect: false
    }
  }

  gotoCoffee = () => {
    this.setState({isLoading:true})
    setTimeout(()=>{
      this.setState({isLoading:false,redirect:true})
    },5000)  //Replace this time with your animation time
  }

  renderCoffee = () => {
    if (this.state.redirect) {
      return <Redirect to='/coffees' />
    }
  }

  render(){
    return(
      <div>
        {this.state.isLoading && <Brewing />}
        {this.renderCoffee()}
        <div onClick={this.gotoCoffee} style={{textDecoration:'underline',color:'blue',cursor:'pointer'}}>Go to Coffee</div>
      </div>
    )
  }
}

I have used Redirect from react-router-dom package for navigation.

Demo

Sign up to request clarification or add additional context in comments.

11 Comments

with your solution, redirection does not render and mount coffee component, it just points to it, but it only actually returns coffee with refresh at browser, redirection is not enough here.
Have you implemented the same way provided in Demo?
What is the issue? Demo is seems to fine and getting redirected after 5sec (animation time).
the issue is that I coffee component is not being mounted here. Only if I refresh at browser. url changes with your solution, but does not render my coffee template.
I have an open bounty about this issue: stackoverflow.com/questions/57532219/…
|
1

There are a few things to consider with your Menus component;

  • returning the <Brewing> JSX from handleClick() won't affect the rendering result of the Menus component, meaning that the animation in <Brewing> won't show as required
  • you'll need to track some state to determine if the <Link> has been clicked by the user at which point, your Menus component can render the <Brewing> component (ie that contains the animation)

One way to approach that in code would be to make the following changes in Coffee.jsx:

import Brewing from './Brewing.jsx';

class Menus extends React.Component {

  constructor(props) {
    super(props);
    
    /* 
    Set inital state to false, which means Brewing wont initially show 
    */
    this.state = { hasBeenClicked : false };
  }

}

handleClick() {
  /* 
  Set hasBeenClicked state of Menus to true after click which will
  cause Brewing to be rendered 
  */
  this.setState({ hasBeenClicked : true });
}

render(){
    return (
     <div>
        <div>
          { /* 
            This is short hand for "if hasBeenClicked = true, then 
            render Brewing here 
            */ }
          { (this.state.hasBeenClicked === true) && <Brewing/> }              
          <Link onClick={this.handleClick} to="/brewing">Coffee</Link>
        </div>
      </div>
    );       
  }
}

export default Menus;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.