Redux-thunk dispatch is not a function error - reactjs

I tried to call an action from my component. But, When I run the call the below action from my component
I got a type error that tells that dispatch is not a function. how to get rid of this error.
action:
import { FETCH_ALL, FETCH_CUSTOMER, CREATE_CUSTOMER, DELETE_ALL, DELETE_CUSTOMER, UPDATE_CUSTOMER } from '../actionTypes';
import * as api from '../api/index';
export const getCustomers = () => async (dispatch) => {
try {
const { data } = await api.getCustomers();
console.log(dispatch);
dispatch({ type: FETCH_ALL, payload: data});
} catch(err) {
console.log(err);
}
};
component:
function Home() {
const customers = useSelector((state) => state.customers);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getCustomers);
},[dispatch]);
return (
<div style={{paddingLeft: '50px', paddingRight: '50px'}}>
<header>
<h1 style={{textAlign: 'center', color: 'green'}}>Customer Relationship Management</h1>
</header>
<button onClick={dispatch(getCustomers)}>Fetch Customers</button>
<div className="heading">
<h3>Customer Details: </h3>
<button className="homePageButtons"><Link className="homePageLinks" to="/add-customer">Add Customer</Link></button>
</div>
<div className="customerTable">
<table>
<thead>
<tr>
<th>ID</th>
<th className="name">First Name</th>
<th className="name">Last Name</th>
<th className="email">Email</th>
</tr>
</thead>
<tbody>
{customers.map((customer) => (
<tr>
<td>customer.id</td>
<td>customer.firstName</td>
<td>customer.lastName</td>
<td>customer.email</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
The below error occurs:
customer.js:11 TypeError: dispatch is not a function
at customer.js:9
I log the dispatch, it is showing the below object...
SyntheticBaseEvent {_reactName: "onClick", _targetInst: null, type: "click", nativeEvent: MouseEvent, target: button, …}
I applied the middleware in the index.js file ad below...
const store = createStore(reducers, compose(applyMiddleware(thunk)));

In useEffect do dispatch(getCustomers()); in the click handler do onClick={()=>dispatch(getCustomers())}

Related

fetching data not showing in table in react

I am create a table and fetching data using axios but in the table I am not able to print the data when I check data is printing in browser but not able to print the particular data to a table format so what should be change in my code?
import { useEffect, useState } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import { Table } from "react-bootstrap";
import axios from "axios";
export default function App() {
const [user, setUser] = useState([]);
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/users", (req, res) => {
res.json();
})
.then((data) => setUser({ ...user, data }))
.catch((error) => console.error(error));
});
return (
<div className="App">
<h3 className="text-primary">User List</h3>
<Table
variant="danger"
striped
bordered
hover
className="shadow-lg text-center"
>
<thead>
<tr>
<th>id</th>
<th>Name</th>
<th>UserName</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{user?.data?.length > 0 &&
user.data.map((user) => {
return (
<tr key={user.id}>
<td>{JSON.stringify(user.data["data"].id)}</td>
<td>{JSON.stringify(user.data["data"].name)}</td>
<td>{JSON.stringify(user.data["data"].username)}</td>
<td>{JSON.stringify(user.data["data"].email)}</td>
</tr>
);
})}
</tbody>
</Table>
{/* <div>{JSON.stringify(user.data["data"])}</div> */}
</div>
);
}
for example
import { useEffect, useState } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import { Table } from "react-bootstrap";
import axios from "axios";
export default function App() {
const [user, setUser] = useState([]);
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((res) => {
setUser(res.data);
})
.catch((error) => console.error(error));
}, []);
return (
<div className="App">
<h3 className="text-primary">User List</h3>
<Table
variant="danger"
striped
bordered
hover
className="shadow-lg text-center"
>
<thead>
<tr>
<th>id</th>
<th>Name</th>
<th>UserName</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{user?.length > 0 &&
user.map((userData) => {
return (
<tr key={userData.id}>
<td>{userData.id}</td>
<td>{userData.name}</td>
<td>{userData.username}</td>
<td>{userData.email}</td>
</tr>
);
})}
</tbody>
</Table>
{/* <div>{JSON.stringify(user)}</div> */}
</div>
);
}
Replace the useEffect code as follow.
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((data) => setUser({ ...user, data }))
.catch((error) => console.error(error));
}, []);
You already know that calling this api will give you an array of users so you can initialise the state as empty array as:
const [users, setUsers] = useState([]);
and when you are using axios then you don't have to use res.json(). axios will do it for you out of the box.
axios
.get("https://jsonplaceholder.typicode.com/users")
.then(({ data }) => setUsers(data))
.catch((error) => console.error(error));
so, after getting data using get method of axios it will return you a promise and you can get data from its data property that is passed an first args. You can directly set state which will be an array of objects.
.then(({ data }) => setUsers(data))
Here I've destructed the object to get only the data property.
Since users will be an array of objects, so you don't have to do any check. You can directly use user.id to get the respective property.
Codesandbox link
export default function App() {
const [users, setUsers] = useState([]);
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/users")
.then(({ data }) => setUsers(data))
.catch((error) => console.error(error));
}, []);
return (
<div className="App">
<h3 className="text-primary">User List</h3>
<Table
variant="danger"
striped
bordered
hover
className="shadow-lg text-center"
>
<thead>
<tr>
<th>id</th>
<th>Name</th>
<th>UserName</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{users.map((user) => {
return (
<tr key={user.id}>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.username}</td>
<td>{user.email}</td>
</tr>
);
})}
</tbody>
</Table>
{/* <div>{JSON.stringify(user.data["data"])}</div> */}
</div>
);
}

How can i change this code to react redux

Here i want to change this code to react redux. How i can change this code using react redux. Kindly provide any solutions for changing this code to react redux using GET method api. As iam new to react js how can i change this code using react redux.
import React from "react";
import { useState, useEffect } from "react";
import { Link } from "react-router-dom";
export default function User() {
const [users, setUsers] = useState([]);
const f = async () => {
const res = await fetch("https://reqres.in/api/userspage=1");
const json = await res.json();
setUsers(json.data);
};
useEffect(() => {
f();
}, []);
const handleLogout = (e) => {
localStorage.clear();
window.location.pathname = "/";
}
return (
<div>
<h1>List Users</h1>
<div>
<button onClick={handleLogout}>Logout</button>
<nav>
<Link to="/Home">Home</Link>
</nav>
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>First_name</th>
<th>Last_name</th>
<th>Email</th>
<th>Avatar</th>
</tr>
</thead>
<tbody>
{users.length &&
users.map((user) => {
return (
<tr>
<td> {user.id}</td>
<td>{user.first_name}</td>
<td> {user.last_name} </td>
<td>{user.email}</td>
<td> <img key={user.avatar} src={user.avatar} alt="avatar" /></td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
);
}

React componentDidMount vs useEffect hooks for API call

When I am trying to make an API call using in useEffect hook (before the component did mount), somehow the state is not getting updated, hence I am getting an error Cannot read property of undefined.
But if I am converting the same logic to a Class component and making the API call in the componentDidMount function, the code works well.
Could anyone tell me why?
Using useEffect
import React from "react";
import axios from "axios";
import { useState, useEffect } from "react";
export default function Customers() {
const [customers, setCustomers] = useState([]);
useEffect(() => {
axios
.get("http://localhost:5000/customers")
.then((res) => {
const data = res.data;
setCustomers(data);
})
.catch((err) => console.log(err));
}, []);
useEffect(() => {
console.log(customers);
}, [customers]);
return (
<div className="container-fluid d-flex flex-column align-items-center justify-content-center">
<div className="top">Customers</div>
<div className="tables">
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Account No</th>
<th scope="col">Name</th>
<th scope="col">E-mail</th>
<th scope="col">Balance</th>
</tr>
</thead>
<tbody>
{customers.data.map((customer) => ( // error on this line.
<tr>
<th scope="row">{customer.account_no}</th>
<td>{customer.name}</td>
<td>{customer.email}</td>
<td>{customer.balance}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
Class Based Component
import React, { Component } from "react";
import axios from "axios";
import "./Customers.css";
export default class Customers extends Component {
state = {
customers: [],
};
componentDidMount() {
axios
.get("http://localhost:5000/customers")
.then((res) => {
res.data.sort();
console.log(res.data);
this.setState({ customers: res.data });
})
.catch((err) => console.log(err));
}
render() {
return (
<div className="container-fluid main w-75 my-4 d-flex flex-column align-items-center">
<div className="top p-4 d-flex justify-content-center">
Our Customers
</div>
<div className="tables w-100">
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Account No</th>
<th scope="col">Name</th>
<th scope="col">E-mail</th>
<th scope="col">Balance</th>
</tr>
</thead>
<tbody>
{this.state.customers.map((customer) => (
<tr>
<th scope="row">{customer.account_no}</th>
<td>{customer.name}</td>
<td>{customer.email}</td>
<td>{customer.balance}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
}
You are not setting state properly in useEffect hook. instead of setCustomers({data:data}); it should be just setCustomers(data);
useEffect(() => {
axios
.get("http://localhost:5000/customers")
.then((res) => {
const data = res.data;
setCustomers(data);
})
.catch((err) => console.log(err));
}, []);
Now because customers is an array, just map over customers instead of customers.data.map.
customers.map((customer)=>{})
So the final code will be
import React from "react";
import axios from "axios";
import { useState, useEffect } from "react";
export default function Customers() {
const [customers, setCustomers] = useState([]);
useEffect(() => {
axios
.get("http://localhost:5000/customers")
.then((res) => {
const data = res.data;
setCustomers(data);
})
.catch((err) => console.log(err));
}, []);
useEffect(() => {
console.log(customers);
}, [customers]);
return (
<div className="container-fluid d-flex flex-column align-items-center justify-content-center">
<div className="top">Customers</div>
<div className="tables">
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Account No</th>
<th scope="col">Name</th>
<th scope="col">E-mail</th>
<th scope="col">Balance</th>
</tr>
</thead>
<tbody>
{customers.map((customer) => (
<tr>
<th scope="row">{customer.account_no}</th>
<td>{customer.name}</td>
<td>{customer.email}</td>
<td>{customer.balance}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
You are declaring your customers state as an array:
const [customers, setCustomers] = useState([]);
But you are passing an object after fetching the data:
setCustomers({ data: data });
That's why your map iteration in the return section fails, because you are setting the state to an object and not an array. If data is an array you should only assign it like this:
setCustomers(data);
The componentDidMount works because you are assigning res.data directly to the customers state and it turns out to be similar to:
setCustomers(data);

No access to "this"

I'm working on a web-application using the MERN stack that displays a table of clients with their name, email, and phone number. I haven't implemented Redux quite yet, but I'm using 'uuid' to supplement data in the table until I can get the redux store set up. So far I have displaying the the list and adding a client to the list working fine, but I am having trouble with the pesky delete button.
This is the current ClientTable component
import React, { Component } from "react";
import { Table, Container, Button } from "reactstrap";
import { connect } from "react-redux";
import {
getClients,
addClient,
editClient,
deleteClient,
} from "../actions/clientActions";
import PropTypes from "prop-types";
const renderClient = (clients, index, id) => {
return (
<tr key={index}>
<td>
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={() => {
this.setState((state) => ({
clients: state.clients.filter((client) => client.id !== id),
}));
}}
>
×
</Button>
</td>
<td>{clients.name}</td>
<td>{clients.email}</td>
<td>{clients.number}</td>
</tr>
);
};
class ClientTable extends Component {
componentDidMount() {
this.props.getClients();
}
onDeleteClick = (id) => {
this.props.deleteClient(id);
};
render() {
const { clients } = this.props.client;
// const { clients } = this.state;
return (
<Container id="listContainer">
<Table
id="listTable"
className="table-striped table-bordered table-hover"
dark
>
<tr class="listRow">
<thead id="tableHeader">
<tr>
<th id="listActions">Actions</th>
<th id="listName">Name</th>
<th id="listEmail">Email</th>
<th id="listNumber">Number</th>
</tr>
</thead>
<tbody class="listRow">{clients.map(renderClient)}</tbody>
</tr>
</Table>
</Container>
);
}
}
ClientTable.propTypes = {
getClients: PropTypes.func.isRequired,
client: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => ({
client: state.client,
});
export default connect(mapStateToProps, {
getClients,
deleteClient,
addClient,
})(ClientTable);
This is the bit of code that is causing me issues
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={() => {
this.setState((state) => ({
clients: state.clients.filter((client) => client.id !== id),
}));
}}
>
×
</Button>
When I click the "delete" button I keep getting TypeError: Cannot read property 'setState' of unedefined
I know the error is because of 'this' isn't bound to anything, but I'm uncertain how to bind it within an onClick event if that is even possible or what even to bind it to. I am just lost as to how to approach this problem. (I'm still quite new to React).
If anyone has any ideas it would be greatly appreciated!
move renderClient function to ClientTable, and use it as a method of this class.
class ClientTable extends Component {
componentDidMount() {
this.props.getClients();
}
renderClient = (clients, index) => {
return (
<tr key={index}>
<td>
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={() => this.onDeleteClient(clients.id)}
>
×
</Button>
</td>
<td>{clients.name}</td>
<td>{clients.email}</td>
<td>{clients.number}</td>
</tr>
);
};
onDeleteClick = (id) => {
this.props.deleteClient(id);
};
render() {
const { clients } = this.props.client;
// const { clients } = this.state;
return (
<Container id="listContainer">
<Table
id="listTable"
className="table-striped table-bordered table-hover"
dark
>
<tr class="listRow">
<thead id="tableHeader">
<tr>
<th id="listActions">Actions</th>
<th id="listName">Name</th>
<th id="listEmail">Email</th>
<th id="listNumber">Number</th>
</tr>
</thead>
<tbody class="listRow">{clients.map(this.renderClient)}</tbody>
</tr>
</Table>
</Container>
);
}
}

action method not getting called

I am trying to get a simple react-redux app to work and I am running into a weird error that I can't figure out. I am trying to simply update my current user's status and handle the store and it doesnt work. changeUserStatus is not getting called
setCurrentUserFirstName - works setCurrentUserHandle - doesn't
export const changeUserStatus = (userid,status) => async (dispatch, getState, { getFirebase }) => {
const firebase = getFirebase()
const databaseRef = firebase.database().ref()
const statusRef = databaseRef.child("users").child(userid).child("user_status")
statusRef.set(status).then(() => {
dispatch({ type: 'CHANGE_USER_STATUS' });
});
}
//home.js file
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { firebaseConnect } from 'react-redux-firebase'
import { compose } from 'redux'
import { Redirect } from 'react-router-dom'
import {changeUserStatus} from '../../store/actions/userActions'
class Users extends Component {
handleAcceptClickEvent1 =(e) =>{
console.log("accepted");
const { userid, status } = this.props;
changeUserStatus(e.target.name,"accepted");
}
handleRejectClickEvent1 =(e) =>{
console.log("rejected");
const { userid, status } = this.props;
changeUserStatus(e.target.name,"rejected");
}
reject =(e) =>{
console.log("rejected");
const { userid, status } = this.props;
this.props.changeUserStatus(userid=e.target.name,status="rejected");
}
UserCard = ({user}) =>{
const status = user.user_status;
let acceptComponent;
let rejectComponent;
if (status == "pending"){
acceptComponent = <td><button type="button" class="btn btn-success green" name ={user.user_id} onClick={this.handleAcceptClickEvent1}>Accept</button></td>
rejectComponent = <td><button type="button" class="btn btn-danger red" name ={user.user_id} onClick={this.handleRejectClickEvent1}>Reject</button></td>
}
else if(status == "accepted"){
acceptComponent = <td>Accepted</td>
rejectComponent = <td></td>
}
else{
acceptComponent = <td></td>
rejectComponent = <td>Rejected</td>
}
return (
<tr>
<th scope="row">{user.user_id}</th>
<td>{user.company_name}</td>
<td>{user.email}</td>
{acceptComponent}
{rejectComponent}
</tr>
)
}
render() {
const { users, auth } = this.props;
if (!auth.uid) return <Redirect to='/login' />
console.log(users);
return (
<div className="dashboard container">
<div className="row">
<div className="project-list section">
<div>
<p>Users</p>
</div>
<table className="table table-striped table-bordered" style={{ width: "100%" }}>
<thead>
<tr>
<th scope="col">User Id</th>
<th scope="col">Company Name</th>
<th scope="col">Email</th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{users && users.map(user => {
return <this.UserCard user={user.value} key={user.value.id} />
})}
</tbody>
</table>
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
users: state.firebase.ordered.users,
auth: state.firebase.auth
}
}
const mapDispatchToProps = (dispatch) => {
return{
changeUserStatus: (userid,status) => dispatch(changeUserStatus(userid,status))
}
}
export default compose(
connect(mapStateToProps),
firebaseConnect({ users: 'users' })
)(Users);
put this and check
export default compose(
connect(mapStateToProps,mapDispatchToProps),
firebaseConnect({ users: 'users' })
)(Users);

Resources