React - Redux dispatcher not mapping - reactjs

I have a several react components in react-redux application. Most of them are working find, but the below "TagItemWidget" does not appear to bind the state or dispatchers to props. I have confirmed that the dispatch function works and fires the reducer. The same function and state can be bound on other components. I have done a trace and observed that the bind function is firing. However, in both "console.log" outputs, props is empty. componentDidMount and render appear to be called only once, when the page loads - never again. What gives?
UPDATE: If I move my <TagItemWidget /> into the spot where <TagItemButton /> is, it populates the dispatchers. Is there a problem with my TagItemButton?
TagItemWidget:
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { tags_list } from "../../actions/tags";
export class TagItemWidget extends React.Component {
static propTypes = {
cases: PropTypes.array.isRequired,
activeCase: PropTypes.string
};
constructor(props) {
super(props);
}
componentDidMount() {
console.log(this)
}
render() {
console.log(this)
return (
<Fragment>
<div key={Math.random} >
{this.props.activeCase}
</div>
</Fragment>
)
}
}
const mapStateToProps = (state) => ({
cases: state.tags.tags,
activeCase: state.cases.activeCase
});
export default connect(mapStateToProps, { tags_list })(TagItemWidget);
The including component, TagItemButton:
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { TagItemWidget } from './TagItemWidget';
export class TagItemButton extends Component {
render() {
return (
<Fragment>
<a href="#" className="list-group-item list-group-item-action" id="controls_tagitem"
data-toggle="modal" data-target="#tagItemModal">
Tag Item
</a>
<div className="modal fade" id="tagItemModal" tabIndex="-1"
role="dialog" aria-labelledby="tagItemModalLabel"
aria-hidden="true">
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title"
id="tagItemModalLabel">
Tag Item
</h5>
<button type="button" className="close"
data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div className="modal-body">
<TagItemWidget />
</div>
</div>
</div>
</div>
</Fragment>
)
}
}
export default TagItemButton;
actions/tags.js
import { TAGS_LIST } from "./types";
import { createMessage, returnErrors } from "./messages";
export const tags_list = ( case_id ) => dispatch => {
if ( case_id != null ) {
console.log("dispatging TAGS_LIST")
axios
.get("/OMNI_api/api/tag/listbycase/?case_id="+case_id)
.then(response => {
dispatch
({
type: TAGS_LIST,
payload: response.data
})
})
}
}

If you are using redux-thunk. Which I think you are.
dispatch needs to be spread from the thunk like so
export const tags_list = ( case_id ) => ({ dispatch }) => {
You need to bindActionCreators
either before passing them to the connect function
const mapDispatch = (dispatch) => bindActionCreators({ tag_list }, dispatch);
export default connect(mapStateToProps, mapDispatch)(TagItemWidget);
inside the constructor
https://redux.js.org/api/bindactioncreators

Related

How to add button cart in shopping cart react redux?

how to add an action when the add button is clicked then the item will display the product?
This code does not display the product when clicked
I've been fiddling with it but it's still an error, who knows, someone here can help me and fix the code and explain it
cartAction.js
import {ADD_TO_CART} from './ActionType';
export const addToCart = (items) =>{
return{
type: ADD_TO_CART,
items //I'm confused about what to do in the action payload here
}
}
cartReducer.js
import ImgT from './images/image-product-1-thumbnail.jpg';
import {ADD_TO_CART} from './ActionType';
const initState = {
items: [
{id:1,title:'title',
brand:cc',
images:ImgT,
desc:'helo world',
price:125.00}
],addItems:[],
total:0
}
const cartReducer= (state = initState,action)=>{
if(action.type === ADD_TO_CART){
return {...state, addItems:state.addItems} //I'm confused about what to do in the action payload here
}
return state
}
export default cartReducer;
cart.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
class Cart extends Component {
render() {
return (
<div>
{this.props.Items.map(item =>{
<div key={item.id}>
{/* <img src={item.images} /> */}
<p>{item.title}</p>
<h4>brand: {item.brand}</h4>
<p>{item.price}</p>
</div>
})
}
</div>
);
}
}
const mapToProps = (state ) =>{
return{
Items:state.addItems}
}
export default connect(mapToProps)(Cart);
Home.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Cart from './Cart';
import {addToCart} from './cartAction';
class Home extends Component{
handleClick = () =>{
this.props.addToCart()
}
render(){
let item = this.props.items.map(item =>{
return(
<div className='card' key={item}>
<img style={{width:'10rem'}} src={item.images}/>
<p className='card-title '>{item.title}</p>
<h2 className='card-title fs-4'>{item.brand}</h2>
<button onClick={() => this.handleClick()} className='btn btn-primary'>Add to cart</button>
<h3 className='fs-5'>{item.price}</h3>
</div>
)
})
return(
<div className="container">
<h3>Home</h3>
{item}
<Cart/>
</div>
)
}
}
const mapToProps = (state) => {
return{
items:state.items,
}
}
const mapDispatchToProps = (dispatch) => {
return{
addToCart: () => dispatch(addToCart())}
}
export default connect(mapToProps,mapDispatchToProps)(Home);

React.js with Redux: Get info from state

I'm coding the app and I can't solve a problem. I have stored user info in the state (when I open Redux DevTools I can see the state -> user: {username: name, role: ...}).
Now in some components, I want to check if logged in user is admin or a user. I have it in that state but how can I load it in some class? When I export a function, I can use const userRole = useSelector(state => state.security.user.role_id); but in a class it makes a problem. Can you help me?
this is my code for User class and I want to show up DELETE button, only if user is an admin:
import React, {Component} from "react";
import PropTypes from "prop-types";
import {connect, useSelector} from "react-redux";
import { Link } from "react-router-dom";
import { deleteUser } from "../../store/actions/userActions";
class User extends Component{
constructor() {
super();}
onDeleteClick(id) {
this.props.deleteUser(id);
}
render() {
const { user } = this.props;
return (
<div className='row entry'>
<div className='col-sm-2'>
<span >{user.username}</span>
</div>
<div className='col-sm-2'>
<span >{user.name}</span>
</div>
<div className='col-sm-2'>
<span>{user.lastname}</span>
</div>
<div className='col-sm-2'>
<span>{user.tag}</span>
</div>
<div className='col-sm-1'>
<span>{user.pay}</span>
</div>
<div className='col-sm-1'>
<span>
{user.role_id}
</span>
</div>
<div className='col-sm-2'>
<Link to={`userlist/edituser:${user.id}`}>
<button><i className="fas fa-user-edit"></i></button>
</Link> | <button onClick={this.onDeleteClick.bind(this, user.id)}><i className="far fa-trash-alt"></i></button>
</div>
</div>
)
}
}
User.propTypes = {
deleteUser: PropTypes.func.isRequired
};
export default connect(
null, { deleteUser }
)(User);
With class components, you can make use of connect HOC with mapStateToProps to access state from redux
class User extends Component{
render() {
const { user, userRole } = this.props;
...
}
}
const mapStateToProps = (state) => {
return {
useRole: state.security.user.role_id,
}
}
export default connect(
mapStateToProps, { deleteUser }
)(User);

Updating state in redux. Unbound function?

I have an application that filters some test on a button click that populates and triggers a dropdown menu. My issue that I'm having is, I want to select the items within the dropdown menu via onclick() that updates the state of the selected test. It's unusual it does not work because when I console.log() the onUpdateSelectedTest I can see that state is being changed and updated but selectedTest remains undefined. Any examples, resources is greatly appreciated.
All files are just snippets.
This is my TestActions.ts
export function UpdateSelectedTest(test: ITest): ToggleTestActionTypes {
return {
type: SELECT_TEST,
payload: test
};
}
This is my Dropdown.tsx
import * as React from "react";
import {
UpdateSelectedTestType,
UpdateSelectedTest
} from "../actions/TestActions";
import { ITestState } from "../models/ITestState";
interface IProps {
onUpdatetoggleTestState: typeof UpdateSelectedTestType;
onUpdateSelectedTest: typeof UpdateSelectedTest;
toggleTestState: ITestState;
}
export class Dropdown extends React.Component<IProps> {
public render() {
let tests = null;
tests = this.props.toggleTestState.tests.filter(
test => test.testType === this.props.toggleTestState.testType
);
return (
<div>
<ul className="nav nav-pills">
<a
className="nav-link dropdown-toggle"
data-toggle="dropdown"
href="#"
role="button"
aria-haspopup="true"
aria-expanded="true"
></a>
<div
className="dropdown-menu show"
x-placement="bottom-start"
style={{
position: "relative",
willChange: "transform",
top: "0px",
left: "0px",
transform: "translate(0px, 40px, 0px"
}}
>
{tests.map(test => (
<a
onClick={() => this.props.onUpdateSelectedTest(test)}
className="dropdown-item"
href="#"
>
<div className="dropdown-divider"></div>
{test.name}: {test.description}
</a>
))}
</div>
</ul>
</div>
);
}
}
The problem occurs here in the Dropdown.tsx
{tests.map(test => (
<a
onClick={() => this.props.onUpdateSelectedTest(test)}
className="dropdown-item"
href="#"
>
<div className="dropdown-divider"></div>
{test.name}: {test.description}
</a>
))}
This is my Apps.tsx
I will past the state of the onUpdateSelectedTest to the ListGroup to be displayed.
import * as React from "react";
import { ToggleButtonGroup } from "./components/ToggleButtonGroup";
import { Dropdown } from "./components/Dropdown";
import { ITestState } from "./models/ITestState";
import { connect } from "react-redux";
import { AppState } from "./store";
import { bindActionCreators } from "redux";
import {
UpdateSelectedTestType,
UpdateSelectedTest
} from "./actions/TestActions";
import { ListGroup } from "./components/ListGroup";
interface IProps {
onUpdatetoggleTestState: typeof UpdateSelectedTestType;
onUpdateSelectedTest: typeof UpdateSelectedTest;
toggleTestState: ITestState;
}
class App extends React.Component<IProps> {
render() {
return (
<div>
<ToggleButtonGroup
toggleTestState={this.props.toggleTestState}
onUpdatetoggleTestState={this.props.onUpdatetoggleTestState}
/>
<Dropdown
toggleTestState={this.props.toggleTestState}
onUpdatetoggleTestState={this.props.onUpdatetoggleTestState}
onUpdateSelectedTest={UpdateSelectedTest}
/>
<ListGroup
toggleTestState={this.props.toggleTestState}
onUpdatetoggleTestState={this.props.onUpdatetoggleTestState}
onUpdateSelectedTest={UpdateSelectedTest}
/>
</div>
);
}
}
const mapStateToProps = (state: AppState) => ({
toggleTestState: state.toggle
});
const mapDispatchToProps = (dispatch: any) => {
return {
onUpdatetoggleTestState: bindActionCreators(
UpdateSelectedTestType,
dispatch
),
onUpdateSelectedTest: bindActionCreators(UpdateSelectedTest, dispatch)
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
This is my toggleButtonReducers.ts
const initialState: ITetsState = {
testType: TestType.test1,
test: dbTests,
question: dbQuestion,
selectedTest: undefined
//selectedQuestion: undefined
};
export function toggleButtonReducer(
state = initialState,
action: ToggleTestActionTypes
) {
switch (action.type) {
case TOGGLE_TEST_TYPE:
return {
...state,
testType: action.payload
};
case SELECT_TEST:
return {
...state,
selectedTest: action.payload
};
default:
return state;
}
}
You likely need to use the dispatch bound action creators. Currently you're calling them but they're not being dispatched.
For example, this line:
onUpdateSelectedTest={UpdateSelectedTest}
Should be:
onUpdateSelectedTest={this.props.onUpdateSelectedTest}
In the below code, from where probes value is coming? I don't see any probes variable in the state or from props.
{probes.map(test => (
<a
onClick={() => this.props.onUpdateSelectedTest(test)}
className="dropdown-item"
href="#"
>
<div className="dropdown-divider"></div>
{test.name}: {test.description}
</a>
))}
i think, instead of probes it should be tests.

TypeError: this.props.decrementCount is not a function

I am trying to make a simple cart counter but getting this error. I am confuse that mapStateToDispatch is working or not. Imported all modules,functions properly but getting only this error when i click the ADD,Remove button
import React,{Component} from 'react';
import './cart.css';
import {product,product1} from './product.js'
import 'bootstrap/dist/css/bootstrap.min.css';
import {incrementCount , decrementCount} from './actions/buttonBehave';
import {connect} from 'react-redux';
import { bindActionCreators } from 'redux'
export class Cart extends Component{
state = {
buttonClicked : false
}
handleButton= () =>{
this.setState({
buttonClicked : true
})
}
render()
{
return(
<div className="cardDiv">
<div className="card" >
<img className="card-img-top" src={product.image} alt="Card image" height="350px" />
<div className="card-body">
<h4 className="card-title">{product.name}</h4>
<p className="card-text">Model : {product.modelName}</p>
<p className="card-text">Price : {product.price}</p>
<a href="#" className="btn btn-primary " onClick={this.handleButton.bind(this)}> {this.state.buttonClicked ? "Add another" : "Add to cart"} </a>
<p className="card-text">Added : {this.props.count}</p>
<button onClick = { () => this.props.incrementCount ()}>Remove</button>
<button onClick = { () => this.props.decrementCount()}>ADD</button>
<p className="card-text">{this.props.count}</p>
</div>
</div>
</div>
);
}
}
const mapStateToProps= (state) =>{
return{
count : state.count
}
}
const mapDispatchToProps = () => {
return {
incrementCount,
decrementCount
}
}
export default connect(mapStateToProps,mapDispatchToProps())(Cart);
You are calling the function instead of passing its reference
export default connect(mapStateToProps,mapDispatchToProps())(Cart);
// ------------------------------------------------------^^--------
change to this
export default connect(mapStateToProps, mapDispatchToProps)(Cart);
An alternative is to just not use mapDispatchToProps at all and use the dispatch your connected component receives
export default connect(mapStateToProps)(Cart);
and then using dispatch
this.props.dispatch(decrementCount())

mapping a dispatch to props when using class

I am trying to dispatch a redux action when an element is clicked. Here is how I currently have things set up
the action
export function removeItem(idx) {
// remove the item at idx
return {
type: "DESTROY_ITEM",
payload: {idx: idx}
}
}
container component
import ItemUi from '../ui/Item';
import { connect } from 'react-redux'
import { removeItem } from '../../actions'
const mapDispatchToProps = dispatch => {
return({
destroyItem: (index) => {
dispatch(
removeItem(index)
)
}
})
}
export default connect(null, mapDispatchToProps)(ItemUi)
ui component
import React, { Component, PropTypes } from 'react';
class Item extends Component {
// ... methods removed for length
render() {
return (
<div>
<span
className="btn btn-primary btn-xs glyphicon glyphicon-trash"
onClick={() => {this.props.destroyItem(this.props.index)}}></span>
</div>
)
}
}
DestroyItem.propTypes = {
onRemoveItem: PropTypes.func
}
export default Item
the top level component
import React, { Component } from 'react';
import Item from './Item'
class App extends Component {
render() {
return(
<div className="container">
<NewItem/>
<ClearAll/>
<div className="panel-group" id="accordion">
{this.props.item.map(this.eachItem)} // <-- renders each item
</div>
</div>
)
}
}
export default App;
When the user clicks the span element shown in the Item ui component I want to fire the destroyItem action passing in the component's index prop. Instead I get the error
TypeError: _this2.props.destroyItem is not a function
Can you please provide some guidance on how I should do this? Let me know if there is any other useful context I can provide.
Try:
const mapDispatchToProps = {
destroyItem: removeItem
}

Resources