Delete item using redux - reactjs

I am trying to get my head around Redux. Doing something like TODO APP with React and Redux. I can add a new task, update its value, but I cannot delete the item correctly. I get an error Unhandled Rejection (TypeError): Cannot read property 'id' of undefined all the time. I pass the ID to the Delete function just like I do in the Update function. Server side works well. The fetch function itself works, and the delete of item from the database works, but an error occurs on the client side Help please guys
const initialState = {
list: [],
}
export default (state = initialState, action) => {
switch (action.type) {
case GET_TASKS: {
return { ...state, list: action.tasks }
}
case CREATE_TASK: {
return { ...state, list: [...state.list, action.task] }
}
case UPDATE_STATUS: {
return {
...state,
list: state.list.map((it) => {
return action.task.id === it.id ? action.task : it
}),
}
}
case DELETE_TASK: {
return {
list: state.list.map((it) => {
return action.task.id !== it.id ? action.task : it
}),
}
}
default:
return state
}
}
export function getTasks() {
return (dispatch) => {
fetch("/api/task")
.then((r) => r.json())
.then(({ data: tasks }) => {
dispatch({ type: GET_TASKS, tasks })
})
}
}
export function deleteTask(id) {
return (dispatch) => {
fetch(`/api/v1/task/${id}`, {
method: "DELETE",
})
.then((r) => r.json())
.then(({ data: task }) => {
dispatch({ type: DELETE_TASK, task })
})
}
}

My first question would be, in your deleteTask method what is being returned here? Does a delete method actually return the task you deleted?
.then(({ data: task }) => {
dispatch({ type: DELETE_TASK, task })
}
If not, another way you can address this is by changing the task in your dispatch to the id you are passing to the deleteTask method:
dispatch({ type: DELETE_TASK, id });
Then use the filter method instead of map in your reducer to return the tasks that don't match that deleted task's id, effectively "deleting" it from your state:
case DELETE_TASK: {
return {
list: state.list.filter((it) => {
return action.id !== it.id;
}),
}
}

Related

Update Values of Multiple Array in Redux

I'm updating an array and I wanted to update the productCode based on the given newCode response. This is by clicking the 'CREATE ALL PRODUCTS' button.
I'm thinking that the problem is on the reducer. It's currently not updating the productCode and newProductCode
Tip: productIndex is the key to finding it
Click Here: CODESANDBOX
Action
export const createAllProducts = (products) => async (dispatch) => {
try {
dispatch({
type: appConstants.CREATE_ALL_PRODUCTS_REQUEST
});
const responses = [
{
config: null,
data: {
newCode: "NEW_AA"
},
headers: null
},
{
config: null,
data: {
newCode: "NEW_FF"
},
headers: null
},
{
config: null,
data: {
newCode: "NEW_GG"
},
headers: null
}
];
const finalResponses = responses.map((product, index) => ({
newProductCode: product.data.newCode,
productCode: product.data.newCode,
productIndex: products[index].productIndex
}));
console.log(finalResponses);
dispatch({
type: appConstants.CREATE_ALL_PRODUCTS_SUCCESS,
payload: finalResponses
});
} catch (error) {
dispatch({
type: appConstants.CREATE_ALL_PRODUCTS_FAILURE
});
}
};
Reducer
case appConstants.CREATE_ALL_PRODUCTS_SUCCESS:
const updatedProducts = state.products.map((product, index) => {
const found = action.payload.find((el) => el.productIndex === index);
return found
? {
...updatedProducts,
productCode: found.productCode,
newProductCode: found.newProductCode
}
: product;
});
return {
...state,
isCreatingAllProducts: false,
products: updatedProducts
};
The issue is with the reducer
case appConstants.CREATE_ALL_PRODUCTS_SUCCESS:
return {
...state,
products: state.products.map((product, index) => {
const found = action.payload.find((el) => el.productIndex === index);
console.log(found);
return found
? {
...product,
productCode: found.productCode,
newProductCode: found.newProductCode
}
: product;
})
};
You used reduce methods with the initial value state, which is the actually old state.
Consider this example:
const state = { history: null }
const payload = [ 'hello', 'equal' ]
//your current reducer
const newState = payload.reduce((acc, cur) => { acc[cur] = cur; return acc } , state)
//the state reference point to the same obj, then redux will not trigger re-render
console.log(newState === state) // true

Error: Invariant failed: A state mutation was detected between dispatches

Reducer :
function listPeopleByName (state = {
getPeopleName:{}
}, action){
switch(action.type){
case C.LIST_PEOPLE_NAME:{
return {
...state
,getPeopleName :action.payload
}
}
default : {}
}
return state
}
Action:
function listPeopleByName(config) {
return function (dispatch) {
ApiService(config)
.then((resp) => {
dispatch({
type: C.LIST_PEOPLE_NAME,
payload: resp.data,
});
})
.catch((error) => {
dispatch({
type: C.LIST_PEOPLE_NAME,
payload: error,
});
});
};
}
ApiService is a function that make an axios request and returns a respones
Dispatching code :
listPeopleByNameFunction = () => {
const listPeopleByNameParam = {
id: someone,
},
let data = {
PeopleId: "snjenfner",
};
let listPeopleByNameCategory = getApiConfig(
"POST",
listPeopleByNameParam,
data
);
this.props.listPeopleByName(listPeopleByNameCategory);
};
const mapDispatchToProps = (dispatch) => ({
listPeopleByName: (config) => dispatch(listPeopleByName(config)),
});
Although I take the previous state (...state) and change the state with the payload i'm getting, it still shows the state is mutated. I would have used reduxtoolkit but this is a way old project that doesn't need to be migrated to reduxtoolkit.

Redux state updated but component not re-rendered (while using promise)

I am using React/Redux.
The main issue is that when i use Promise then component is not re-rendered, whereas the code is working fine when promise code is not used.
Action Creator
const updateColor = colorobj => {
return dispatch =>
new Promise(function(resolve, reject) {
dispatch(fetchColorBegin());
axios
.post(config.APIURL.color.update, colorobj)
.then(response => {
const data = response.data;
if (data.errorno !== 0) {
dispatch(fetchColorFailure(data.errormsg));
reject(data.errormsg);
} else {
dispatch(updateColorSuccess(colorobj));
resolve('Color Updated');
}
})
.catch(error => {
dispatch(fetchColorFailure(error.message));
reject(error.message);
});
});
};
Reducer
case UPDATE_COLOR_SUCCESS:
const todoIndex = state.data.findIndex(todo => todo.id === action.payload.id);
return update(state, {
loading: { $set: false },
data: { [todoIndex]: { $merge: action.payload } },
error: { $set: null}
});
Component
the state is updated but the component is not updated.
const handleEditOk = values => {
let colorobj = {
id: state.updateData.id,
colorname: values.colorname,
colorcode: values.colorcode,
};
dispatch(updateColor(colorobj))
.then(response => {
message.success(response);
onCancel();
})
.catch(error => {
message.error(error);
});
};
The component update itself only on commenting the promise code.
The problem now is that it is not showing success/failure message.
const handleEditOk = values => {
let colorobj = {
id: state.updateData.id,
colorname: values.colorname,
colorcode: values.colorcode,
};
dispatch(updateColor(colorobj))
// .then(response => {
// message.success(response);
// onCancel();
// })
// .catch(error => {
// message.error(error);
// });
};
Kindly suggest.

React updating data of an array but changes not appears

I have a array of groups which is brought from API, and is displayed on a table..
return(
<Table
data={props.data}
columns={columns}
noHeader={true}
/>
)
const mapStateToProps = state => ({
data: state.Table.arrayGroups,
})
In this table I have a column that has a button that enable and disable a group, that calls this action:
export const handleStatus = (data, status, id, endPoint, ActionType) => {
let index = data.findIndex( array => array.id === id);
console.log(index)
if (status) {
console.log('entrei disable')
data[index].enable = false
console.log(data)
return dispatch => {
httpPut(`${endPoint}/${id}/disable`)
.then(resp => {
return [
dispatch({
type: ActionType,
payload: data
})
]
})
.catch(error => {
console.log(error)
})
}
}
else {
console.log('entrei enable')
data[index].enable = true
return dispatch => {
httpPut(`${endPoint}/${id}/enable`)
.then(resp => {
return [
dispatch({
type: ActionType,
payload: data
})
]
})
.catch(error => {
console.log(error)
})
}
}
}
On this action I'm basically getting data array and changing a value inside of it.. and update the arrayGroups.. like this :
case 'MODIFIED_GROUPS':
return { ...state, arrayGroups: action.payload }
the issue is : after doing it table continuous displaying the previous array Data
Connect by react-redux is a PureComponent . What it means is that unless the props change it doesn't trigger a re-render. And it performs a shallow equality and reference check.
Since in your case you are mutating the data, the update isn't triggereing.
Clone the data obejct and update it
export const handleStatus = (data, status, id, endPoint, ActionType) => {
let index = data.findIndex( array => array.id === id);
console.log(index)
const newData = [...data]; // shallow cloning data
if (status) {
console.log('entrei disable')
newData[index].enable = false
console.log(newData);
return dispatch => {
httpPut(`${endPoint}/${id}/disable`)
.then(resp => {
return [
dispatch({
type: ActionType,
payload: newData
})
]
})
.catch(error => {
console.log(error)
})
}
}
else {
console.log('entrei enable')
newData[index].enable = true
return dispatch => {
httpPut(`${endPoint}/${id}/enable`)
.then(resp => {
return [
dispatch({
type: ActionType,
payload: newData
})
]
})
.catch(error => {
console.log(error)
})
}
}
}

How do I update Redux store with POST response?

I have an application that is using React, Redux (Redux Thunk). I having an issue updating the state in the reducer after a fetch post inserts into a table.
I am trying to dispatch an action and pass some information from the action to the reducer but not able to do so. I am specifically trying to pass the fetch response into the dispatch. I have a key named res within my dispatch. I set it to a value of data but I believe this value of data is undefined.
export function insertSearchTerm(searchTerm) {
console.log('C')
return (dispatch) => {
fetch('http://localhost:3001/api/v1/searches?searchterm='+ searchTerm, {
headers: {
'Content-Type':'application/json', //headers - tells y9ou that it is json
},
method:'POST',
body: JSON.stringify(searchTerm) //stringifies searchTerm
}).then(res => console.log('Inside insertSearch Term resp', res.json()))
.then(data => {
dispatch({
type:'INSERT_SEARCH_TERM',
searchTerm: searchTerm,
res : data
})
}
)
}
console.log('E')
}
export default function allSearchTermsReducer(state = {allSearchTerms: []}, action) {
switch (action.type) {
case 'ALL_SEARCHES':
console.log("Allsearch reducer",action.payload);
return {...state, allSearchTerms: action.payload}
case 'INSERT_SEARCH_TERM':
console.log('insert search term action', action)
return {
...state,
allSearchTerms: [...state.allSearchTerms, action.id, action.searchTerm, action.created_at] }
default:
return state
}
};
In your action-creator, for the first .then block you are returning a console.log() not the data itself. So there's no data to dispatch in the proceeding .then block. Should be updated to:
export function insertSearchTerm(searchTerm) {
console.log('C')
return (dispatch) => {
fetch('http://localhost:3001/api/v1/searches?searchterm='+ searchTerm, {
headers: {
'Content-Type':'application/json', //headers - tells y9ou that it is json
},
method:'POST',
body: JSON.stringify(searchTerm) //stringifies searchTerm
}).then(res => res.json())
.then(data => {
dispatch({
type:'INSERT_SEARCH_TERM',
searchTerm: searchTerm,
res : data
})
}
)
}
console.log('E')
}

Resources