I am trying hard to remove an array. But it is not work. After delete my array length and data remain same.
This is my frontend react web page
renderAdmin = (id) => {
if(this.props.auth.user.userType==='normal') return(<td></td>);
return (
<React.Fragment>
<td>
<button onClick={() => this.props.changeStatus(id)}
className="ui button" >Change Status</button>
</td>
<td>
<button onClick={() => this.props.deleteUser(id)}
className="ui button" >Delete User</button>
</td>
</React.Fragment>
);
}
Here i am taking id of my array.
Now this is my redux action creator
export const deleteUser = (id) => (dispatch,getState) => {
const user = JSON.parse(localStorage.getItem('user'));
axios.delete(`/api/users/remove/${id}`, {
headers: {
'Authorization': `${user.token}`
}
}).then((res) => {
console.log(res.data);
dispatch({
type: 'DELETE_USER',
payload: res.data
})
dispatch({
type: 'CREATE_ERROR',
payload: 'User Delete'
})
})
.catch((error) => {
console.error(error)
})
}
Here first i remove it from backend server. That works fine. Then i send res.data to my reducer payload. DELETE_USER not working well. but CREATE_ERROR works fine.
This is my reducer
export default function (state = [] , action) {
// console.log(action)
switch(action.type) {
case 'ALL_USER' : return action.payload;
case 'EDIT_USER' :
return state.map(user=>{
if(user._id === action.payload._id){
return action.payload;
}
else {
return user;
}
});
case 'DELETE_USER' :
return state.filter(user=>
user !== action.payload
)
default : return state;
}
}
After pressing delete button, data remove from server but redux store always remain same. Please help me.
Thank You.
It might be due to the objects not being truly equal try filtering on the id instead:
return state.filter(user=>
user._id !== action.payload._id
)
Or check for deep equality.
Related
Seen some similiar posts, haven't found my answer. I have this code trying to delete an object from an array, with the backend set up so it works on Post Man, when I started working with Redux I encountered this issue.
action.js:
export const deletePost = (id) => async (dispatch) => {
try {
await axios.delete(`api/posts/${id}`);
dispatch({
type: DELETE_POST,
payload: { id },
});
dispatch(setAlert('Post removed', 'success'));
} catch (err) {
dispatch({
type: POST_ERROR,
payload: { msg: err.response.statusText, status: err.response.status },
});
}
};
Reducer has been combined in the root reducer file
Reducer.js:
case DELETE_POST:
return {
...state,
posts: state.posts.filter((post) => post._id !== payload), ///Removes the post from the array
loading: false,
};
component.js:
{!auth.loading && user === auth.user._id && (
<button
onClick={() => deletePost(_id)}
type='button'
className='btn btn-danger'
>
<i className='fas fa-delete-left'></i>
</button>
)}
I've tried debugging, and it seems that the deletePost() action doesn't even start running when I click the button.
I found out that this code actually deletes, but in action.js file when I dispatch the DELETE_POST type, it then runs the catch immedietaly. The problem is in the try{dispatch()} function, as what I want to log before it actually logs, but what I want to log after doesn't.
Edit: it says that dispatch is not a function for every dispatch in action.js file...
So I make an API call to server to get the currentUser,
useEffect(() => {
loadUser()
},[])
Since behaviour of React is like render first run lifecycle methods second, at first, my selector for user returns null which what I expect.
However I still got user is null error, so this is my code =>
const isAuthenticated = useSelector(state => state.auth.isAuthenticated)
const user = useSelector(state => state.auth.user)
const authLinks = (
<nav className="auth-navbar">
<div className="auth-navbar__dropdown">
<button type="button" className="dropdown-btn" onClick={dropdown}><img src={profilephoto}></img></button>
<div className="dropdown-menu">
<Link to={`u/${user.username}`} className="dropdown-link">Profile</Link>
<Link to="/settings" className="dropdown-link">Settings</Link>
<Link to="/" onClick={onClickHandler} className="dropdown-link">Logout</Link>
</div>
</div>
</nav>
)
if (user) {
return (
<header className="header">
<Link to="/" className="logo" >
<img src={logo} alt="logo"/>
</Link>
{isAuthenticated ? authLinks : guestLinks}
</header>
)
} else {
return <p>loading..</p>
}
Questions like this have been asked before on stackoverflow but solutions are similar to mine and it still doesn't work. Please help me.
P.S: the default of user is null in the reducer.
EDIT: The action creator to load user =>
export const loadUser = () => (dispatch) => {
dispatch({ type: USER_LOADING })
const config = {
withCredentials: true
}
axios.get('http://127.0.0.1:8000/auth/user/', config)
.then(res => {
dispatch({
type: USER_LOADED,
payload: res.data
})
}).catch(err => {
console.log(err)
dispatch({
type: AUTH_ERROR
})
})
}
Normally user loads without error =>
reducer =>
const initialState = {
isAuthenticated: false,
isLoading: false,
user: null,
}
export default function(state=initialState, action){
switch(action.type){
case USER_LOADING:
return {
...state,
isLoading: true
}
case USER_LOADED:
return {
...state,
isAuthenticated: true,
isLoading: false,
user: action.payload
}
I think you need to make authLinks a function which executes and returns the relevant JSX only when user exists. As it is, the variable will try to access the property user.username before it has been initialised.
const authLinks = () => (
...
);
And then call it in the return.
{isAuthenticated ? authLinks() : guestLinks}
When I click delete I get the Can not read property 'id' of null error.
I am confused.* How to pass the id so only the component I clicked on (delete button) is removed?**
Reducer:
const notesReducer = (state = notes, action, id) => {
switch (action.type) {
case 'ADD':
return [...state, action.newItem]
case 'DELETING':
//const newState = [...state.filter((note) => note !== action.note)]
const newState = [...state]
newState.filter((note) => note.id !== action.payload.id)
//newNote.pop()
default:
return state
}
}
Action
export const add = (id) => {
return {
type: 'ADD',
}
}
export const deleting = (id) => {
return {
type: 'DELETING',
}
}
Component
<div>
{notes.map((item, index) => (
<div>
<Select></Select>
<Dialog key={uuid()}></Dialog>
<Button
key={uuid()}
onClick={deleteNote}
>
Delete
</Button>
</div>
))}
</div>
dispatch({ type: 'ADD', mynote }),
dispatch({ type: 'DELETING' })
Based on your current implementation, you need to pass note id to
dispatch({ type: 'DELETING', note.id })
Also, in reducer, you need to return modified state.
case 'DELETING':
return state.filter((note) => note.id !== id)
As an advice, you actually don't use actions you defined, because you directly dispatch with type. So, keep in mind that it's a better approach to write actions and fire them using mapDispatchToProps.
Im trying to delete messages written in a form with react and redux.
The id props is sent correctly as I can see in console, but I only get my error msg when I press the delete button.
This is the button component:
import React from 'react'
import { useDispatch } from 'react-redux'
import { messages, fetchDeleteMessage } from 'reducer/messages'
export const DeleteBtn = (props) => {
const dispatch = useDispatch()
const handleDeleteMessageClick = () => {
dispatch(fetchDeleteMessage(props.message.id))
console.log('delete message', (props.message.id))
}
return (
<button className="delete-btn"
onClick={handleDeleteMessageClick}>
<span role="img" aria-label="delete">✖︎</span>
</button>
)
}
This is my reducer where I try to fetch and delete a specific message upon its id, the id is passed on to the fetch correctly, but nothing happens and I cant see whats wrong and feel I tried it all (....apparently not)
import { createSlice } from '#reduxjs/toolkit'
export const messages = createSlice({
name: 'messages',
initialState: {
allMessages: [],
},
reducers: {
deleteMessage: (state, action) => {
console.log('deleteMessageState', state)
console.log('deleteMessageAction', action)
//finds the task
//remove it from the array
state.allMessages = state.allMessages.filter((message) => message.id !== action.payload)
},
}
})
//****** fetch DELETE message ********
export const fetchDeleteMessage = (id) => {
return (dispatch) => {
fetch(`http://localhost:3004/messages/${id}`, {
method: 'DELETE',
statusCode: 204,
headers: {
'Content-Type': 'application/json'
}
})
.then((res) => res.json())
.then(json => {
console.log('DELETE', json, id)
dispatch(messages.action.deleteMessage(id))
})
.catch(err => {
console.error('error', err)
dispatch(messages.actions.deleteMessage({ error: `Error, failed to delete` }))
})
}
}
`````
To delete an item you should return state
return state.allMessages.filter((message) => message.id !== action.payload)
instead of
state.allMessages = state.allMessages.filter((message) => message.id !== action.payload)
I'm working on a todo app and everything works fine when it first loads in. However, when I add a new todo and the store updates, I get the unique key warning, when the key is defined in the array components:
render() {
const todoList = this.props.todos.map(todo => {
return <Todo todo={todo} key={todo._id}/>
})
return (
<div className={styles.todoContainer}>
{todoList}
</div>
);
}
Todo Component:
return (
<div className={styles.todo}>
<h2 className={styles.todoText}>{props.todo.name}</h2>
</div>
);
Adding todo:
//actions.js
export function addTodo(todo){
let config = {
headers: {
token: localStorage.getItem('token')
}
};
return function(dispatch){
return axios.post('http://localhost:8082/api/todos/create', todo, config)
.then(msg => {
dispatch({type: ADD_TODO, payload: todo})
})
.catch(err => console.log(err));
}
}
//reducer.js
case ADD_TODO:
const data = [...state.data];
data.push(action.payload);
return {
...state,
data: data
};
Is this a problem I should worry about fixing, or is it a bug? Thanks!