Code-shark1
Code-shark1

Reputation: 47

React.js history.push in a separate function?

Can you help me with React.js history.push function?

I have a icon which can be pressed. The onClick calls handleRemoveFavourite function which filters out the current item from localStrorage and sets the updated string to storage. This works fine.

After the storage update is done the program should reroute the user to the root page /favourites. The reroute works well in the bottom example. But how to do this in the handleRemoveFavourites function?

This is the code I would like to have

handleRemoveFavourite = () => {
    const { name } = this.props.workout;
    let savedStorage = localStorage.saved.split(",");
    let cleanedStorage = savedStorage.filter(function(e) {
      return e !== name;
    });
    localStorage.setItem("saved", cleanedStorage.toString());
    history.push("/favourites")
  };

  renderHeartIcon = () => {
    return (
      <Route
        render={({ history }) => (
          <Rating
            icon="heart"
            defaultRating={1}
            maxRating={1}
            onClick={this.handleRemoveFavourite}
          />
        )}
      />
    );
  };

The rerouting works fine with just this:

  renderHeartIcon = () => {
    return (
      <Route
        render={({ history }) => (
          <Rating
            key={1}
            icon="heart"
            defaultRating={1}
            maxRating={1}
            size="large"
            onClick={() => history.push("/favourites")}
          />
        )}
      />
    );
  };

The whole component looks like this:

import React from "react";
import {
  Container,
  Grid,
  Icon,
  Label,
  Table,
  Header,
  Rating,
  Segment
} from "semantic-ui-react";
import { Link, Route } from "react-router-dom";

export default class WorkoutComponent extends React.PureComponent {
  renderChallengeRow = workouts => {
    let { reps } = this.props.workout;
    reps = reps.split(",");

    return workouts.map((item, i) => {
      return (
        <Table.Row key={item.id}>
          <Table.Cell width={9}>{item.name}</Table.Cell>
          <Table.Cell width={7}>{reps[i]}</Table.Cell>
        </Table.Row>
      );
    });
  };

  handleRemoveFavourite = () => {
    const { name } = this.props.workout;
    let savedStorage = localStorage.saved.split(",");
    let cleanedStorage = savedStorage.filter(function(e) {
      return e !== name;
    });
    localStorage.setItem("saved", cleanedStorage.toString());
    // history.push("/favourites");
  };

  renderHeartIcon = () => {
    return (
      <Route
        render={({ history }) => (
          <Rating
            key={1}
            icon="heart"
            defaultRating={1}
            maxRating={1}
            size="large"
            onClick={this.handleRemoveFavourite}
          />
        )}
      />
    );
  };

  render() {
    const { name, workouts } = this.props.workout;
    const url = `/savedworkout/${name}`;
    return (
      <Grid.Column>
        <Segment color="teal">
          <Link to={url}>
            <Header as="h2" to={url} content="The workout" textAlign="center" />
          </Link>
          <Table color="teal" inverted unstackable compact columns={2}>
            <Table.Body>{this.renderChallengeRow(workouts)}</Table.Body>
          </Table>
          <br />
          <Container textAlign="center">
            <Label attached="bottom">{this.renderHeartIcon()}</Label>
          </Container>
        </Segment>
        <Link to="/generate">
          <Icon name="angle double left" circular inverted size="large" />
        </Link>
      </Grid.Column>
    );
  }
}

Upvotes: 0

Views: 1449

Answers (4)

Marcelo Rubim
Marcelo Rubim

Reputation: 137

Changing to this.props.history.push("/favourites"); should works.

EDITED

Is your component inside a Route? If so, this.props.history will works. I tested changing your class to run on my project.

import React from 'react';
import ReactDOM from 'react-dom';
import {
  Container,
  Grid,
  Icon,
  Label,
  Table,
  Header,
  Rating,
  Segment
} from "semantic-ui-react";
 import { Link, Route, BrowserRouter  as Router } from "react-router-dom";

export default class WorkoutComponent extends React.Component {
  static defaultProps = {
      workout: {
          reps: "1,2,3,4",
          workouts: []
      },

  }
  renderChallengeRow = workouts => {
    let { reps } = this.props.workout;
    reps = reps.split(",");

    return workouts.map((item, i) => {
      return (
        <Table.Row key={item.id}>
          <Table.Cell width={9}>{item.name}</Table.Cell>
          <Table.Cell width={7}>{reps[i]}</Table.Cell>
        </Table.Row>
      );
    });
  };

  handleRemoveFavourite = () => {
    const { name } = this.props.workout;
    //let savedStorage = localStorage.saved.split(",");
    // let cleanedStorage = savedStorage.filter(function(e) {
    //   return e !== name;
    // });
    // localStorage.setItem("saved", cleanedStorage.toString());
    this.props.history.push("/favourites");
  };

  renderHeartIcon = () => {
    return (
      <Route
        render={({ history }) => (
          <Rating
            key={1}
            icon="heart"
            defaultRating={1}
            maxRating={1}
            size="large"
            onClick={this.handleRemoveFavourite}
          />
        )}
      />
    );
  };

  render() {
      console.log(this.props)
    const { name, workouts } = this.props.workout;
    const url = `/savedworkout/${name}`;
    return (

          <Grid.Column>
        <Segment color="teal">
          <Link to={url}>
            <Header as="h2" to={url} content="The workout" textAlign="center" />
          </Link>
          <Table color="teal" inverted unstackable compact columns={2}>
            <Table.Body>{this.renderChallengeRow(workouts)}</Table.Body>
          </Table>
          <br />
          <Container textAlign="center">
            <Label attached="bottom">{this.renderHeartIcon()}</Label>
          </Container>
        </Segment>
        <Link to="/generate">
          <Icon name="angle double left" circular inverted size="large" />
        </Link>
      </Grid.Column>
    );
  }
}
ReactDOM.render(
<Router>        
    <Route path="/" component={ WorkoutComponent }/>
</Router>, document.getElementById('root'));

Upvotes: 0

Aseem Upadhyay
Aseem Upadhyay

Reputation: 4537

The problem you are facing is, you are providing <Route> with the history prop, so that it is propagated on the component function call. But you are not propagating it to the handleRemoveFavourite function.

You'll need to wrap this. handleRemoveFavourite in an anonymous function call. Like

          onClick={() => this.handleRemoveFavourite(history)}

and then accept it as a valid argument in your function

handleRemoveFavourite = (history) => {...}

that should solve it

Upvotes: 1

Ibrahim
Ibrahim

Reputation: 336

Since you are using react-router you can use withRouter to achive this.

import { withRouter } from 'react-router-dom'

Wrap the with class name with withRouter.

Like this:

instead of doing like this:

export default class App .....

Separate this like:

class App ...

At the end of the line:

export default withRouter(App)

Now you can use like this:

handleRemoveFavourite = () => {
  const { name } = this.props.workout;
  let savedStorage = localStorage.saved.split(",");
  let cleanedStorage = savedStorage.filter(function(e) {
    return e !== name;
  });
  localStorage.setItem("saved", cleanedStorage.toString());
  this.props.history.push("/favourites");
};

You can remove Route from renderHearIcon():

renderHeartIcon = () => {
    return (
        <Rating
          key={1}
          icon="heart"
          defaultRating={1}
          maxRating={1}
          size="large"
          onClick={this.handleRemoveFavourite}
        />
    );
  };

Upvotes: 2

gu mingfeng
gu mingfeng

Reputation: 1050

onClick={this.handleRemoveFavourite}
=> 
onClick={()=>this.handleRemoveFavourite(history)}

handleRemoveFavourite = () => {
=>
handleRemoveFavourite = (history) => {

Upvotes: 1

Related Questions