reactjs – TypeError: this.props.navigate is not a function

I am new to React.js and I am getting the following error “TypeError: this.props.navigate is not a functionwhile calling this.props.navigate(/todos/${id}) in updateTodoClicked(id) function under ToDoList Component

The same function working working fine in LoginComponent.

Error Log Screenshot:

ToDoList Component:

import React, { Component } from 'react'
import TodoDataService from '../../api/todo/TodoDataService.js'
import AuthenticationService from './AuthenticationService.js'
import moment from 'moment'

class ToDoList extends Component {
    constructor(props) {
        console.log('constructor')
        super(props)
        this.state = {
            todos: [],
            message: null
        }
        this.deleteTodoClicked = this.deleteTodoClicked.bind(this)
        this.updateTodoClicked = this.updateTodoClicked.bind(this)
        this.addTodoClicked = this.addTodoClicked.bind(this)
        this.refreshTodos = this.refreshTodos.bind(this)
    }

    componentWillUnmount() {
        console.log('componentWillUnmount')
    }

    shouldComponentUpdate(nextProps, nextState) {
        console.log('shouldComponentUpdate')
        console.log(nextProps)
        console.log(nextState)
        return true
    }

    componentDidMount() {
        console.log('componentDidMount')
        this.refreshTodos();
        console.log(this.state)
    }

    refreshTodos() {
        let username = AuthenticationService.getLoggedInUser()
        TodoDataService.retriveAllTodos(username)
            .then(
                response => {
                    //console.log(response);
                    this.setState({ todos: response.data })
                }
            )
    }

    deleteTodoClicked(id) {
        let username = AuthenticationService.getLoggedInUser()
        //console.log(id + " " + username);
        TodoDataService.deleteTodo(username, id)
            .then(
                response => {
                    this.setState({ message: `Delete of todo ${id} Successful` })
                    this.refreshTodos()
                }
            )

    }

    addTodoClicked() {
        this.props.navigate(`/todos/-1`)
        //this.props.history.push(`/todos/-1`)
    }

    updateTodoClicked(id) {
        console.log('update ' + id)
        this.props.navigate(`/todos/${id}`)
    }

    render() {
        console.log('render')
        return (
            <div>
                <h1>List Todos</h1>
                {this.state.message && <div class="alert alert-success">{this.state.message}</div>}
                <div className="container">
                    <table className="table">
                        <thead>
                            <tr>
                                <th>Description</th>
                                <th>Target Date</th>
                                <th>IsCompleted?</th>
                                <th>Update</th>
                                <th>Delete</th>
                            </tr>
                        </thead>
                        <tbody>
                            {
                                this.state.todos.map(
                                    todo =>
                                        <tr key={todo.id}>
                                            <td>{todo.description}</td>
                                            <td>{moment(todo.targetDate).format('YYYY-MM-DD')}</td>
                                            <td>{todo.done.toString()}</td>
                                            <td><button className="btn btn-success" onClick={() => this.updateTodoClicked(todo.id)}>Update</button></td>
                                            <td><button className="btn btn-warning" onClick={() => this.deleteTodoClicked(todo.id)}>Delete</button></td>
                                        </tr>
                                )
                            }
                        </tbody>
                    </table>
                    <div className="row">
                        <button className="btn btn-success" onClick={this.addTodoClicked}>Add</button>
                    </div>
                </div>
            </div>
        )
    }
}

export default ToDoList

TodoComponent:

import React, {Component} from "react";
import moment from 'moment'; 
import {Formik, Form, Field} from 'formik';

class TodoComponent extends Component { 
    constructor(props) {
    super(props)
    this.state = {
        id : this.props.params.id,
        description : 'Learn Forms',
        targetDate : moment(new Date()).format('YYYY-MM-DD')
    }
}


render() {
   return <div>
       <h1>Todo</h1>
       <div className="container"> 
            <Formik>
                {
                    (porps) => (
                        <Form>
                            <fieldset className="form-group">
                                <label>Description</label>
                                <Field className="from-control" type="text" name="description"></Field>
                            </fieldset>
                            <fieldset className="form-group">
                                <label>Target Date</label>
                                <Field className="from-control" type="date" name="targetDate"></Field>
                            </fieldset>
                        </Form>
                    )
                }    
            </Formik>            
        </div>
       </div>
    }
}

export default TodoComponent

TodoApp:

enter code here
import React, {Component} from "react";
import {BrowserRouter as Router, Route, Routes} from 'react-router-dom'
import withNavigation from './WithNavigation.jsx' 
import withParams from "./WithParams.jsx";
import AuthenticationRoute from "./AuthenticatedRoute.jsx"
import LoginComponent from "./LoginComponent.jsx"
import ToDoList from "./ListTodos.jsx"
import HeadderComponent from "./HeaderComponent.jsx"
import FooterComponent from "./FooterComponent.jsx"
import ErrorComponent from "./ErrorComponent.jsx"
import LogoutComponent from "./LogoutComponent.jsx"
import WelcomeComponent from "./WelcomeComponent.jsx"
import TodoComponent from "./TodoComponent.jsx"

class ToDoApp extends Component {
    render() {
        const LoginComponentWithNavigation = withNavigation(LoginComponent);
        const WelcomeComponentWithParams = withParams(WelcomeComponent);
        const HeaderComponentWithNavigation = withNavigation(HeadderComponent);
        const TodoComponentWithParamsAndNavigation = withParams(withNavigation(TodoComponent));

        return(
            <div className="TodoApp">
                <Router>
                    <HeaderComponentWithNavigation></HeaderComponentWithNavigation>
                    <Routes>
                        <Route path="/" element={<LoginComponentWithNavigation />}/>
                        <Route path="/login" element={<LoginComponentWithNavigation />} />
                        <Route path="/welcome/:name" element={<AuthenticationRoute><WelcomeComponentWithParams/></AuthenticationRoute>} /> 
                        <Route path="/todos/:id" element={<AuthenticationRoute><TodoComponentWithParamsAndNavigation /></AuthenticationRoute>} />
                        <Route path="/todos" element={<AuthenticationRoute><ToDoList /></AuthenticationRoute>}/>
                        <Route path="/logout" element={<AuthenticationRoute><LogoutComponent /></AuthenticationRoute>}/>
                        <Route path="*" element={<ErrorComponent />} />
                    </Routes>
                    <FooterComponent></FooterComponent>
                </Router>
                {/*<LoginComponent/>
                <WelcomeComponent/>*/}
            </div>
        )
    }
}

export default ToDoApp;

WithNavigation:

import React from "react";
import { useNavigate } from "react-router-dom";

function withNavigation(Component) {
  return props => <Component {...props} navigate={useNavigate()} />;
}

export default withNavigation

WithParams:
import React from “react”; import { useParams } from “react-router-dom”;

function withParams(Component) {
  return props => <Component {...props} params={useParams()} />;
}
 
export default withParams

I am NOT getting any error while calling this.props.navigate(/welcome/${this.state.username}) function in LoginComponent Component

Login Component

    import React, {Component} from "react";
import AuthenticationService from "./AuthenticationService.js"

class LoginComponent extends Component {
    constructor(props) {
        super(props)
        this.state = {
            username: 'in28Minutes',
            password: '',
            hasLoginFailed: false,
            showSuccessMessage: false
        }
        this.handleChange = this.handleChange.bind(this)
        this.loginClicked = this.loginClicked.bind(this)
    }

    handleChange(event) {
        this.setState({[event.target.name]:event.target.value})
    }

    loginClicked() {
        if(this.state.username==='in28Minutes' && this.state.password==='dummy') {
            AuthenticationService.registerSuccessfullLogin(this.state.username, this.state.password)
            this.props.navigate(`/welcome/${this.state.username}`)
            this.setState({hasLoginFailed:false})
            this.setState({showSuccessMessage:true})
        }
        else{
            console.log("Login Failed")
            this.setState({showSuccessMessage:false})
            this.setState({hasLoginFailed:true})
        }
    }

    render() {
        return(
            <div>
                <h1>Login</h1>
                <div className="container">
                    {/*<ShowInvalidCredentials hasLoginFailed={this.state.hasLoginFailed}/>*/}
                    {<ShowSuccessMessage showSuccessMessage={this.state.showSuccessMessage}/>}
                    {this.state.hasLoginFailed && <div className="alert alert-warning">Invalid Credentails</div>}
                    {/*{this.state.showSuccessMessage && <div>Login Successful</div>}*/}
                    User Name: <input type="text" name="username" value={this.state.username} onChange={this.handleChange}></input>
                    <div className="container">
                    Password: <input type="password" name="password" value={this.state.password} onChange={this.handleChange}></input>
                    </div>
                    <button className="btn btn-success" onClick={this.loginClicked}>Login</button>
                </div>
            </div>
        )
    }
}

function ShowSuccessMessage(props) {
    if(props.showSuccessMessage) {
        return <div>Login Success</div>
    } else {
        return null
    }
}

export default LoginComponent

Leave a Comment