Renak
Renak

Reputation: 39

'withRouter' has been imported but still getting TypeError: Cannot read property 'push' of undefined

Here is my component code for adding a user.

import React, { Component } from 'react';
import UserDataService from '../service/UserDataService';
import { withRouter} from 'react-router-dom';

class ListUsersComponent extends Component {

    constructor(props) {
        super(props)
        this.state = {
            users: [], 
            message: null
        }
        this.refreshUsers = this.refreshUsers.bind(this)
        this.deleteUserClicked = this.deleteUserClicked.bind(this)
        this.addUserClicked = this.addUserClicked.bind(this)
        this.createUser = this.createUser.bind(this)
    }

    componentDidMount() {
        this.refreshUsers()
    }

    refreshUsers() {
        UserDataService.retrieveAllUsers()
            .then(
                response => {
                    console.log(response)
                    this.setState({ users: response.data })
                }
            )
    }

    deleteUserClicked(id) {
        UserDataService.deleteUser(id)
            .then(
                response => {
                    this.setState({ message: `Delete of ${id} Successful` })
                    this.refreshUsers()
                }
            )
    }

    addUserClicked() {
        this.props.history.push(`/courses/-1`)
    }

    createUser(user) {
        UserDataService.addUser(user)
            .then(
                response => {
                    this.setState({ message: `User ${user.firstName} ${user.lastName} Successfully added`})
                    this.refreshUsers()
                }
            )
    }

    render() {
        return (
            <div className="container">
                <h3> All Users </h3>
                {this.state.message && <div class="alert alert-success">{this.state.message}</div>}
                <div className="container">
                    <table className="table">
                        <thead>
                            <tr>
                                <th>Id</th>
                                <th>FirstName</th>
                                <th>LastName</th>
                                <th>Email</th>
                                <th></th>
                                <th></th>
                                <th></th>
                            </tr>
                        </thead>
                        <tbody>
                            {
                                this.state.users.map(
                                    user =>
                                        <tr key={user.id} >
                                            <td>{user.id}</td>
                                            <td>{user.firstName}</td>
                                            <td>{user.lastName}</td>
                                            <td>{user.email}</td>
                                            <td>
                                                <img src={user.imagePath}></img>
                                            </td>
                                            <td>
                                                <button className="btn btn-warning" onClick={() => this.deleteUserClicked(user.id)}>Delete</button>
                                            </td>
                                            <td>
                                                <button className="btn btn-success" onClick={() => this.updateUserClicked(user.id)}>Update</button>
                                            </td>
                                        </tr>
                                )
                            }
                        </tbody>
                    </table>
                </div>
                <div className="row">
                    <button className="btn btn-success" onClick={this.addUserClicked}>Add</button>
                </div>
            </div>
        )
    }
}

export default ListUsersComponent

with simple button html

 <div className="row">
    <button className="btn btn-success" onClick={this.addUserClicked}>Add</button>
 </div>

But when I click the add button I get

TypeError: Cannot read property 'push' of undefined
ListUsersComponent.addUserClicked
http://localhost:3000/static/js/main.chunk.js:188:24
  185 | }
  186 | 
  187 | addUserClicked() {
> 188 |   this.props.history.push("/user/-1");
      |                      ^  189 | }

What am i missing here? Im pretty sure all my version are current. Ive posted all the code for ListUsersComponent as requested. I have to type some more info because I have too much code now. Any other needs to help assess my issue

Here is my controller as requested

    private UserRepository repo;

    @GetMapping("/users")
    public Iterable<User> getAllUsers() {
        return repo.findAll();
    }

    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        Optional<User> user = repo.findById(id);
        if (user == null) {
            ResponseEntity.notFound().build();
            return null;
        }

        ResponseEntity.noContent().build();
        return user.get();
    }

Upvotes: 1

Views: 239

Answers (2)

Hamza El Aoutar
Hamza El Aoutar

Reputation: 5657

withRouter is a higher order component, and it doesn't work by just importing it.

You actually need to wrap your component in withRouter for it to have access to this.props.history:

export default withRouter(ListUsersComponent);

You also need to wrap App with Router:

import { Router } from "react-router";
import { createBrowserHistory } from "history";

const history = createBrowserHistory();

ReactDOM.render(
  <Router history={history}>
    <App />
  </Router>,
  document.getElementById('root')
)

Upvotes: 2

Dhananjai Pai
Dhananjai Pai

Reputation: 6015

Read Docs

You can get access to the history object’s properties and the closest 's match via the withRouter higher-order component. withRouter will pass updated match, location, and history props to the wrapped component whenever it renders.

for the props to be available in the component, in addition to importing the function, you must call withRouter(Component)

in your case,

export default withRouter(ListUsersComponent);

Upvotes: 0

Related Questions