value of state increment twice in reducer.js file - reactjs

Order is an array of Objects and there is a key 'count' inside each variable. When ADD_ITEM_IN_ORDER case is executed than the count of particular object should be increment by 1. But, in this case, when the particular item is already present in the array than the value of count of that item incrementing by 2, which should not happen(it should increment by 1).
reducer.js
export const initialState = {
Order: [],
};
const reducer = (state, action) => {
console.log(action);
switch (action.type) {
case "ADD_ITEM_IN_ORDER":
const tempOrder1 = [...state.Order];
const index1 = state.Order.findIndex((item) => item.id === action.item.id);
if (index1 >= 0) {
console.log("before",tempOrder1[index1].Count);
tempOrder1[index1].Count += 1;
return { ...state, Order: tempOrder1 };
}
else {
console.log("New item added");
return {
...state,
Order: [...state.Order, action.item]
};
}
default:
return state;
}
};
export default reducer;
action file
import React from 'react';
import VegIcon from '../Images/VegIcon.png';
import NonVegIcon from '../Images/NonVegIcon.png';
import { useStateValue } from '../StateProvider';
import { db } from '../firebase';
const CartMenu = (props) => {
const [{ Order }, dispatch] = useStateValue();
const add = () => {
dispatch({
type: "ADD_ITEM_IN_ORDER",
item: {
id: props.id,
menuCollectionName:props.menuCollectionName,
VegNonV: props.VegNonV,
Menu: props.Menu,
Price: props.Price,
Count: 1,
// RestuarantId: props.restuarantId
}
});
console.log(Order);
};
const remove = () => {
dispatch({
type: "REMOVE_ITEM_FROM_ORDER",
item: {
id: props.id, // id of a dish
restuarantId: props.restuarantId
}
});
};
return (
<div className='Menu_Display'>
<div className='Menu_Display_subsection1'>
{props.VegNonV === "Veg" ?
<img className="Menu_Veg_NonVeg" src={VegIcon} />
:
<img className="Menu_Veg_NonVeg" src={NonVegIcon} />
}
<div className='Menu_Name'>{props.Menu}</div>
</div>
<div className="Menu_Add_Button" >
<div className="Menu_minus" onClick={remove}>−</div>
<span>{props.Count}</span>
<div className="Menu_plus" onClick={add}>+</div>
</div>
<div className='Menu_Price'>
<span></span>
<span>₹{Math.round(props.Price * props.Count * 100) / 100}</span>
</div>
</div>
);
};
export default CartMenu;
StateProvider.js
//setup data layer
// we need this to track the basket data
import React,{createContext,useContext,useReducer} from 'react';
export const StateContext = createContext();
//Build Provider
export const StateProvider = ({reducer,initialState,children}) =>
(
<StateContext.Provider value = {useReducer(reducer,initialState)}>
{children}
</StateContext.Provider>
);
export const useStateValue = () => useContext(StateContext);

The context API broadcasts updates when it notices a change in the value. Since you are invoking useReducer within the value props, that returns an array (state value and dispatch function), it is this, that is likely causing double dispatch. I recommend you re-write your Provider logic.
import React,{createContext,useContext,useReducer} from 'react';
export const StateContext = createContext({ //Make sure to export this
Order:[], //Will be consuimg the state value from here
addItem:(arg)=>{} //This function will be hooked to a dispatch function below
});
//Build Provider
export const StateProvider = ({reducer,initialState,children}) =>
{
const [state,dispatchFn] = useReducer(reducer,initialState)
const addItemHandler = (item) => {
dispatchFn(item)
}
return(<StateContext.Provider value = {{Order:state.Order,addItem:addItemHandler}}>
{children}
</StateContext.Provider>)
};
You can then wrap your root component with the context provider component StateProvider so that all the components can access the state values.
In your index.js wrap the component like this:
import {StateProvider} from './path/to/provider'
ReactDOM.render(<StateProvider><App/></StateProvider>,doucment.getElementById("root"))
You can then use the context state and dispatch function from useContext hook by, passing the context variable.
In your action file:
import {useContext},React from 'react'; //Import use context
import {StateContext} from './path/to/state/context'
import VegIcon from '../Images/VegIcon.png';
import NonVegIcon from '../Images/NonVegIcon.png';
import { db } from '../firebase';
const CartMenu = (props) => {
const order_ctx = useContext(StateContext);
const add = () => {
order_ctx.addItem({
type: "ADD_ITEM_IN_ORDER",
item: {
id: props.id,
menuCollectionName:props.menuCollectionName,
VegNonV: props.VegNonV,
Menu: props.Menu,
Price: props.Price,
Count: 1,
// RestuarantId: props.restuarantId
}
});
console.log(Order);
};
const remove = () => {
order_ctx.rmItem({ //Note: rmItem method is not added to createContext, but this is just to demonstrate how state update methods can be invoked by using the context instance.
type: "REMOVE_ITEM_FROM_ORDER",
item: {
id: props.id, // id of a dish
restuarantId: props.restuarantId
}
});
};
return (
<div className='Menu_Display'>
<div className='Menu_Display_subsection1'>
{props.VegNonV === "Veg" ?
<img className="Menu_Veg_NonVeg" src={VegIcon} />
:
<img className="Menu_Veg_NonVeg" src={NonVegIcon} />
}
<div className='Menu_Name'>{props.Menu}</div>
</div>
<div className="Menu_Add_Button" >
<div className="Menu_minus" onClick={remove}>−</div>
<span>{props.Count}</span>
<div className="Menu_plus" onClick={add}>+</div>
</div>
<div className='Menu_Price'>
<span></span>
<span>₹{Math.round(props.Price * props.Count * 100) / 100}</span>
</div>
</div>
);
};
export default CartMenu;
And also since, your state contains only an array of orders, you can just return the updated array without having to override the previous state.
In your reducer:
case "ADD_ITEM_IN_ORDER":
const tempOrder1 = [...state.Order];
const index1 = state.Order.findIndex((item) => item.id === action.item.id);
if (index1 >= 0) {
console.log("before",tempOrder1[index1].Count);
tempOrder1[index1].Count += 1;
return { Order: [...tempOrder1] }; //Return updated array only
}
else {
console.log("New item added");
return {
Order: [...state.Order, action.item] //Return updated array only
};
}
default:
return state;
}

Related

passing object using context and doing iteration with map

This is a simple question but I couldn't reach the final result after a lot of attempts. The problem is that I want to pass an object in context and use it in another file. And then do an iteration and create a specific element for each value.
App.jsx
const [activities, setActivity] = useState([
{
key: Math.random() * Math.random(),
name: 'Hello',
}
]);
const inputValue = useRef(null);
const addActivity = () => {
const activity = {
key: Math.random() * Math.random(),
name: inputValue.current.value,
};
setActivity(activities.concat(activity));
};
const value = {
// I want to pass this parameter - only activities has problem (Activity.jsx <h1>)
// I can't achieve activities.name in Activity.jsx
activities: [...activities],
functions: {
addActivity: addActivity
},
ref: {
inputValue: inputValue
}
};
<Context.Provider
value={value}
>
Context.js
export const Context = createContext();
Activity.jsx
const { activities, functions, ref } = useContext(Context);
return (
<section className="activity-container">
<input type="text" ref={ref.inputValue} />
<button onClick={functions.addActivity}>add!</button>
{
activities.map(activity => (
<h1>activity.name</h1>
))
}
</section>
);
I believe this is what you want:
// Sharing data through context
Context file:
// Context.js
import React, { useState, useRef, createContext } from "react";
export const DataContext = createContext();
const getRandom = () => Math.random() * Math.random();
const defaultValue = {
key: getRandom(),
name: "Hello"
};
const ContextProvider = ({ children }) => {
const [activities, setActivity] = useState([defaultValue]);
const inputValue = useRef(null);
const addActivity = () => {
const activity = {
key: getRandom(),
name: inputValue.current.value
};
setActivity([...activities, activity]);
};
const value = {
activities: [...activities],
functions: { addActivity },
ref: { inputValue }
};
return <DataContext.Provider value={value}>{children}</DataContext.Provider>;
};
export default ContextProvider;
Hook to read from context:
// useDataContext
import { useContext } from "react";
import { DataContext } from "./Context";
const useDataContext = () => {
const contextValue = useContext(DataContext);
return contextValue;
};
export default useDataContext;
Child Element where you want to receive the value from context:
// Child.js
import React from "react";
import useDataContext from "./useDataContext";
const Child = () => {
const data = useDataContext();
return (
<>
{data.activities.map((val, idx) => (
<div key={idx}>Name is {val.name}</div>
))}
</>
);
};
export default Child;
And the App container:
// App.js
import Child from "./Child";
import ContextProvider from "./Context";
export default function App() {
return (
<div className="App">
<ContextProvider>
<Child />
</ContextProvider>
</div>
);
}
I've created a sandbox for you to test.
You should make sure that the Activity.jsx component is wrapped with context provider, to get the proper value from the context.
I tried in this codesandbox, and it's working properly. You can refer to this and check what you are missing.

How to Revert to the Original Background Color of previously Clicked Components When Clicking Another in React

What I am trying to achieve is, as mentioned in the title, to revert the component's background color when another entry component in the sidebar gets clicked. I use React Context API for state management. The initial state contains an array of objects named numbers which has two elements (id & number) and current. On Sidebar.js, it renders the SidebarEntry component iterating the numbers array.
I know why I am stuck at this point. It is because there is no way that I can change the state of the previously clicked component unless it gets clicked again. The following code snippet is what I reproduced my issue.
reducer.js
export const initialState = {
numbers: [
{
id: 1,
number: 101
},
{
id: 2,
number: 102
},
{
id: 3,
number: 103
},
],
current: null
}
const reducer = (state, action) => {
switch(action.type) {
case 'CHANGE_STATE':
return {
...state,
current: action.current
};
default:
return state;
}
}
export default reducer;
StateProvider.js (This wraps in index.js with initialState and reducer arguments)
import React, { createContext, useContext, useReducer } from "react";
export const StateContext = createContext();
export const StateProvider = ({ reducer, initialState, children }) => (
<StateContext.Provider value={useReducer(reducer, initialState)}>
{children}
</StateContext.Provider>
);
export const useStateValue = () => useContext(StateContext);
Sidebar.js
const Sidebar = () => {
const [{ numbers }] = useStateValue();
return (
<div className="sidebar">
{
numbers.map(number => (
<SidebarEntry key={number.id} number = {number.number} />
))
}
</div>
)
}
export default Sidebar
SidebarEntry.js
const SidebarEntry = ({ number }) => {
const [{ current }, dispatch] = useStateValue();
const [selected, setSelected] = useState(false);
const changeState = (e) => {
e.preventDefault();
dispatch({
type: "CHANGE_STATE",
current: {number}
});
setSelected(!selected);
}
return (
<div className="sidebarEntry">
<h3
className={selected && "sidebarEntry__color"}
onClick={changeState}
>
{number}
</h3>
</div>
)
}
export default SidebarEntry
Sidebar & SidebarEntry
When clicking 101, then clicking 102 (101's background color is supposed to be back to gray)
The problem is that when you dispatch a new active value in redux, you are actually changing the redux state.
But you are not changing the current state of the component selected.
I would delete this state altogether and do it like this:
const SidebarEntry = ({ number }) => {
const [{ current }, dispatch] = useStateValue();
const changeState = (e) => {
e.preventDefault();
dispatch({
type: "CHANGE_STATE",
current: {number}
});
setSelected(!selected);
}
return (
<div className="sidebarEntry">
<h3
className={current === number && "sidebarEntry__color"}
onClick={changeState}
>
{number}
</h3>
</div>
)
}
export default SidebarEntry
This should work for you

How to write a function in reducer in React-Redux

I am working on a React project, In that I have to perform Increment operation and I am writing
That's logic in a store, but I don't now how to stop it's Increment after 6.
So someone please help me how to write logic to stop Incrementing after 6, its initial value
Is 1. When I am clicking the plus icon it has to Increment but it has to stop Incrementing
after number 6. For this project I am using React-Redux.
This is Buttontypes.js
export const additionVariable = 'ADDITION'
This is Buttonactions.js
import { additionVariable } from './Buttontypes';
export const addition = () => {
return {
type: additionVariable
}
}
This is Buttonreducer.js
import { additionVariable } from './Buttontypes';
const initialState = {
value: 1
}
const additionReducer = (state = initialState, action) => {
switch(action.type) {
case additionVariable: return {
...state,
value: state.value + 1
}
default: return state
}
}
export default additionReducer
This is store.js
import { createStore } from 'redux';
import mainReducer from './Button/Buttonreducer';
const store = createStore(mainReducer);
export default store
This is App.js
import React from 'react';
import './App.css';
import { connect } from 'react-redux';
import { addition } from './Redux/Button/Buttonactions';
function App(props) {
return (
<div className="container">
<div className='row'>
<div className='adultbox pr-2'>
<div className='onebox'>
<span className='adultminus'>-</span>
</div>
<div className='twobox'>
<span className='adultvalue'>{props.value}</span>
</div>
<div className='threebox'>
<span onClick={props.Fun} className='adultplus'>+</span>
</div>
</div>
</div>
</div>
);
}
const mapStateToProps = state => {
return {
value: state.value
}
}
const mapDispatchToProps = dispatch => {
return {
Fun: () => dispatch(addition())
}
}
export default connect(mapStateToProps,mapDispatchToProps)(App)
try this for your reducer :
import { additionVariable } from './Buttontypes';
const initialState = {
value: 1
}
const additionReducer = (state = initialState, action) => {
switch(action.type) {
case additionVariable: return {
...state,
value: state.value <= 6 ? state.value + 1 : state.value
}
default: return state
}
}
export default additionReducer
In addition to what already suggested about the reducer, I would advice you to add a check in mapDispatchToProps and (optional) disable the + if the value is equal to 6:
const mapDispatchToProps = dispatch => {
return {
Fun: (value) => {
if (value < 6 {
dispatch(addition())
}
}
}
}
Then, in App.js:
<div className='threebox'>
<span onClick={() => props.Fun(props.value)} className='adultplus'>+</span>
</div>

Custom react hook triggers api call multiple times

I cannot figure out how to handle my function components calling my api repeatedly. I have two components which retrieve data, one of them calls the api twice. Once before the second component once after.
I am using a custom react hook and axios get method to retrieve the data. My two components are are nested. The first component when loads and fetches data. Inside this component is a child component which when renders it fetches data right before passing the first set of data as props to another child component. When it completes loading it reloads the first child component which again calls the api for data. I understand the function components reload on state change. I would be happy for it to not call the api a second time. Is there a way to check if it already has data and bypass the api call?
Custom hook to retrieve data
import React, { useState, useEffect, useReducer } from "react";
import axios from "axios";
const dataFetchReducer = (state, action) => {
switch (action.type) {
case "FETCH_INIT":
return { ...state, isLoading: true, hasErrored: false };
case "FETCH_SUCCESS":
return {
...state,
isLoading: false,
hasErrored: false,
errorMessage: "",
data: action.payload
};
case "FETCH_FAILURE":
return {
...state,
isLoading: false,
hasErrored: true,
errorMessage: "Data Retrieve Failure"
};
case "REPLACE_DATA":
// The record passed (state.data) must have the attribute "id"
const newData = state.data.map(rec => {
return rec.id === action.replacerecord.id ? action.replacerecord : rec;
});
return {
...state,
isLoading: false,
hasErrored: false,
errorMessage: "",
data: newData
};
default:
throw new Error();
}
};
const useAxiosFetch = (initialUrl, initialData) => {
const [url] = useState(initialUrl);
const [state, dispatch] = useReducer(dataFetchReducer, {
isLoading: false,
hasErrored: false,
errorMessage: "",
data: initialData
});
useEffect(() => {
let didCancel = false;
const fetchData = async () => {
dispatch({ type: "FETCH_INIT" });
try {
let result = await axios.get(url);
if (!didCancel) {
dispatch({ type: "FETCH_SUCCESS", payload: result.data });
}
} catch (err) {
if (!didCancel) {
dispatch({ type: "FETCH_FAILURE" });
}
}
};
fetchData();
return () => {
didCancel = true;
};
}, [url]);
const updateDataRecord = record => {
dispatch({
type: "REPLACE_DATA",
replacerecord: record
});
};
return { ...state, updateDataRecord };
};
export default useAxiosFetch;
Main component which renders the "CompaniesDropdown" twice inside
CompaniesDropdown is one of three dropdowns within the ListFilterContainer component but the only one which calls the api more than once. The other two dropdowns load by selection of the CompaniesDropdown.
import React, { useMemo, useEffect, useContext } from "react";
import InvoiceList from "../src/Components/Lists/InvoiceList";
import useAxiosFetch from "../src/useAxiosFetch";
import { ConfigContext } from "./_app";
import ListFilterContainer from "../src/Components/Filters/InvoiceFilters";
// import "../css/ListView.css";
const Invoices = props => {
const context = useContext(ConfigContext);
useEffect(() => {
document.title = "Captive Billing :: Invoices";
});
const {
data,
isLoading,
hasErrored,
errorMessage,
updateDataRecord
} = useAxiosFetch("https://localhost:44394/Invoice/GetInvoices/false", []);
const newInvoicesList = useMemo(
() => data
// .filter(
// ({ sat, sun }) => (speakingSaturday && sat) || (speakingSunday && sun)
// )
// .sort(function(a, b) {
// if (a.firstName < b.firstName) {
// return -1;
// }
// if (a.firstName > b.firstName) {
// return 1;
// }
// return 0;
// }),
// [speakingSaturday, speakingSunday, data]
);
const invoices = isLoading ? [] : newInvoicesList;
if (hasErrored)
return (
<div>
{errorMessage} "Make sure you have launched "npm run json-server"
</div>
);
if (isLoading) return <div>Loading...</div>;
const dataProps = {
data: invoices,
titlefield: "invoiceNumber",
titleHeader: "Invoice Number:",
childPathRoot: "invoiceDetail",
childIdField: "invoiceId",
childDataCollection: "invoiceData"
};
var divStyle = {
height: context.windowHeight - 100 + "px"
};
return (
<main>
<ListFilterContainer />
<section style={divStyle} id="invoices" className="card-container">
<InvoiceList data={dataProps} />
</section>
</main>
);
};
Invoices.getInitialProps = async ({ req }) => {
const isServer = !!req;
return { isServer };
};
export default Invoices;
Actual result is described above. My main concern is to not have the api calls more than once.
Here is some additional code to help. It is the filter control mentioned above. It, as you will notice really just contains dropdowns and a text box. The first dropdown is the one that calls the api twice. The second two are not visible until that one is selected.
import React, { useState, useMemo } from "react";
import CompaniesDropdown from "../Dropdowns/CompaniesDropdown";
import LocationsDropdown from "../Dropdowns/LocationsDropdown";
import AccountsDropdown from "../Dropdowns/AccountsDropdown";
import Search from "./SearchFilter/SearchFilter";
const InvoiceFilters = props => {
const [company, setCompany] = useState("");
const [location, setLocation] = useState(undefined);
const [account, setAccount] = useState(undefined);
const handleClientChange = clientValue => {
setCompany(clientValue);
};
const handleLocationsChange = locationValue => {
setLocation(locationValue);
};
const handleAccountsChange = AccountValue => {
setAccount(AccountValue);
};
return (
<section className="filter-container mb-3">
<div className="form-row">
<div className="col-auto">
<CompaniesDropdown change={e => handleClientChange(e)} />
</div>
<div className="col-auto">
<LocationsDropdown
selectedCompany={company}
change={e => handleLocationsChange(e)}
/>
</div>
<div className="col-auto">
<AccountsDropdown
selectedCompany={company}
change={e => handleAccountsChange(e)}
/>
</div>
<div className="col-auto">
<Search />
</div>
</div>
</section>
);
};
InvoiceFilters.getInitialProps = async ({ req }) => {
const isServer = !!req;
return { isServer };
};
export default InvoiceFilters;
Also the datalist
import React from "react";
import Link from "next/link";
import InvoiceListRecord from "./InvoiceListRecord";
const InvoiceList = props => {
let dataCollection = props.data.data;
return dataCollection.length == 0 ? "" : dataCollection.map((item, index) => {
return (
<section key={"item-" + index} className="card text-left mb-3">
<header className="card-header">
<span className="pr-1">{props.data.titleHeader}</span>
<Link
href={
"/" +
props.data.childPathRoot +
"?invoiceId=" +
item[props.data.childIdField]
}
as={
"/" +
props.data.childPathRoot +
"/" +
item[props.data.childIdField]
}
>
<a>{item[props.data.titlefield]}</a>
</Link>{" "}
</header>
<div className="card-body">
<div className="row">
<InvoiceListRecord
data={item}
childDataCollection={props.data.childDataCollection}
/>
</div>
</div>
</section>
);
});
};
InvoiceList.getInitialProps = async ({ req }) => {
console.log("Get Intitial Props works: Invoices Page!");
const isServer = !!req;
return { isServer };
};
export default InvoiceList;
and the list items component.
import React from "react";
const InvoiceListRecord = props => {
var invoiceData = JSON.parse(props.data[props.childDataCollection]);
return invoiceData.map((invKey, index) => {
return (
<div className="col-3 mb-1" key={"item-data-" + index}>
<strong>{invKey.MappedFieldName}</strong>
<br />
{invKey.Value}
</div>
);
});
};
export default InvoiceListRecord;
The API is not called more than once if the url is the same. It just gets the value from data variable. The api call is not made again, unless the url changes.
I created an example from your code, changing all the unknown components to div. I added a console.log in the useEffect of the useAxiosFetch hook. And to re-render the component, I added a button to increment the count.
You'll see that the console.log from the hook is printed only once, even though the component re-renders on every button click. The value just comes from the data variable from the hook and the api call is not made again and again.

Redux action not firing on move with react-dnd

I'm pretty new to React and Redux and very new to react-dnd, and I think I'm doing something wildly incorrect here. Although there are other similar posts out there I can't quite find a solution in them.
I'm working on a Kanban board app that is somewhat based on the one found at https://survivejs.com/react/implementing-kanban/drag-and-drop/ though that version uses Alt.js and I'm using Redux.
The problem: when dragging a component, the action function is called but the case in the reducer (MOVE_TICKET) is not. This seems to be the case regardless of the content of the action function.
I linked the action to a click event and in this instance the action and reducer worked as expected. This leads me to think that it must be a problem with the way I've set up the Ticket component with the dnd functions.
Ticket.js:
import React from "react"
import {compose} from 'redux';
import { DragSource, DropTarget } from 'react-dnd';
import ItemTypes from '../constants/ItemTypes';
import { moveTicket } from "../actions/ticketsActions"
const Ticket = ({
connectDragSource, connectDropTarget, isDragging, isOver, onMove, id, children, ...props
}) => {
return compose (connectDragSource, connectDropTarget)(
<div style={{
opacity: isDragging || isOver ? 0 : 1
}} { ...props } className = 'ticket'>
<h3 className = 'summary'> { props.summary } </h3>
<span className = 'projectName'> { props.projectName }</span>
<span className = 'assignee'> { props.assignee } </span>
<span className = 'priority'> { props.priority } </span>
</div>
);
};
const ticketSource = {
beginDrag(props) {
return {
id: props.id,
status: props.status
};
}
};
const ticketTarget = {
hover(targetProps, monitor) {
const targetId = targetProps.id;
const sourceProps = monitor.getItem();
const sourceId = sourceProps.id;
const sourceCol = sourceProps.status;
const targetCol = targetProps.status;
if(sourceId !== targetId) {
targetProps.onMove({sourceId, targetId, sourceCol, targetCol});
}
}
};
export default compose(
DragSource(ItemTypes.TICKET, ticketSource, (connect, monitor) => ({
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging()
})),
DropTarget(ItemTypes.TICKET, ticketTarget, (connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver()
}))
)(Ticket)
ticketsReducer.js:
export default function reducer(state={
tickets: [],
fetching: false,
fetched: false,
error: null,
}, action) {
switch (action.type) {
case "MOVE_TICKET": {
return [{...state, tickets: action.payload}]
}
}
return state
}
ticketsActions.js
import store from '../store';
export function moveTicket({sourceId, targetId, sourceCol, targetCol}) {
const columns = Object.assign({}, store.getState().tickets.tickets)
const sourceList = columns[sourceCol];
const targetList = columns[targetCol];
const sourceTicketIndex = sourceList.findIndex(ticket => ticket.id == sourceId);
const targetTicketIndex = targetList.findIndex(ticket => ticket.id == targetId);
if(sourceCol === targetCol){
var arrayClone = sourceList.slice();
arrayClone.splice(sourceTicketIndex, 1);
arrayClone.splice(targetTicketIndex, 0, sourceList[sourceTicketIndex]);
columns[sourceCol] = arrayClone;
}
return function(dispatch){
dispatch({type: "MOVE_TICKET", payload: columns});
}
}
Column.js (where each Ticket component is rendered)
import React from "react"
import uuid from "uuid"
import { connect } from "react-redux"
import ColumnsContainer from "./ColumnsContainer"
import Ticket from "./ticket"
import { moveTicket } from "../actions/ticketsActions"
#connect((store) => {
return {
columns: store.columns.columns
};
})
export default class Column extends React.Component {
console(){
console.log(this)
}
render(){
const tickets = this.props.tickets.map((ticket, id) =>
<Ticket
key = {uuid.v4()}
id={ticket.id}
summary = { ticket.summary }
assignee = { ticket.assignee }
priority = { ticket.priority }
projectName = { ticket.displayName }
onMove={ moveTicket }
status= { ticket.status }
/>
)
return(
<div key = {uuid.v4()} className = { this.props.className }>
<h2 key = {uuid.v4()}>{ this.props.title }</h2>
<ul key = {uuid.v4()}>{ tickets }</ul>
</div>
)
}
}
If anyone can see where I'm going wrong I could really use some assistance.
You are not connecting the moveTicket action to redux's dispatcher.
You'll have to do something like:
#connect((store) => {
return {
columns: store.columns.columns
};
}, {moveTicket})
export default class Column extends React.Component {
// ...
// use this.props.moveTicket instead of moveTicket
The second parameter to connect is called mapDispatchToProps, which will do the dispatch(actionFn) for you.
You might want to name the bound action differently, e.g.
#connect((store) => {
return {
columns: store.columns.columns
};
}, {connectedMoveTicket: moveTicket})
// then use this.props.connectedMoveTicket

Resources