I am making a React app where I need to add Redux using Hooks. Currently, I am stuck in making a POST request and can't figure out after going through the internet, how to make it work. I am on my way to understand how the Redux works and I will be happy for any help on this to make it work, so I can understand what is missing and how to send the data. My components:
App.js:
import { useState } from "react";
import { connect } from 'react-redux';
import "./App.css";
import Posts from "./components/posts";
import { addPost } from "./store/actions/postAction";
function App() {
const [title, setTitle] = useState("");
const [body, setBody] = useState("");
const handleSubmit = (event) => {
event.preventDefault();
const post = {
title: title,
body: body,
}
addPost(post);
setTitle('');
setBody('');
alert("Post added!");
};
return (
<div className="App">
<Posts />
<form onSubmit={handleSubmit}>
<label>
Mew post:
<input
type="text"
name="title"
placeholder="Add title"
value={title}
onChange={e => setTitle(e.target.value)}
/>
<input
type="text"
name="body"
placeholder="Add body"
value={body}
onChange={e => setBody(e.target.value)}
/>
</label>
<button type="submit">Add</button>
</form>
</div>
);
}
export default connect()(App);
postAction.js
import axios from "axios";
import { GET_POSTS, ADD_POST, POSTS_ERROR } from "../types";
const url = "http://localhost:8002/";
export const getPosts = () => async (dispatch) => {
try {
const response = await axios.get(`${url}posts`);
dispatch({
type: GET_POSTS,
payload: response.data,
});
} catch (error) {
dispatch({
type: POSTS_ERROR,
payload: error,
});
}
};
export const addPost = (post) => (dispatch) => {
try {
const response = axios.post(`${url}`, {post});
dispatch({
type: ADD_POST,
payload: response.data,
});
} catch (error) {
dispatch({
type: POSTS_ERROR,
payload: error,
});
}
};
postReducer.js
import { ADD_POST, GET_POSTS, POSTS_ERROR } from "../types";
const initialState = {
posts: []
};
const postReducer = (state = initialState, action) => {
switch (action.type) {
case GET_POSTS:
return {
...state,
posts: action.payload
};
case ADD_POST:
return {
...state,
posts: action.payload
};
case POSTS_ERROR:
return {
error: action.payload
};
default:
return state;
}
};
export default postReducer;
posts.js
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { getPosts } from "../store/actions/postAction";
const Posts = () => {
const dispatch = useDispatch();
const postsList = useSelector((state) => state.postsList);
const { loading, error, posts } = postsList;
useEffect(() => {
dispatch(getPosts());
}, [dispatch]);
return (
<>
{loading
? "Loading..."
: error
? error.message
: posts.map((post) => (
<div className="post" key={post.id}>
<h4>{post.title}</h4>
<p>{post.body}</p>
</div>
))}
</>
);
};
export default Posts;
App.js -> change to export default connect(null, {addPost})(App);
Related
i want to implement update user password form using react-router-dom v6 but this code is not working..
please please.. put your suggestion or explain me about my mistakes on this code.
userReducer.js
import {
UPDATE_PASSWORD_REQUEST,
UPDATE_PASSWORD_SUCCESS,
UPDATE_PASSWORD_RESET,
UPDATE_PASSWORD_FAIL,
CLEAR_ERRORS,
} from "../Constants/userConstant";
export const profileReducer = (state = {}, action) => {
switch (action.type) {
case UPDATE_PASSWORD_REQUEST:
return {
...state,
loading: true,
};
case UPDATE_PASSWORD_SUCCESS:
return {
...state,
loading: false,
isUpdated: action.payload,
};
case UPDATE_PASSWORD_FAIL:
return {
...state,
loading: false,
error: action.payload,
};
case UPDATE_PASSWORD_RESET:
return {
...state,
isUpdated: false,
};
case CLEAR_ERRORS:
return {
...state,
error: null,
};
default:
return state;
}
};
userAction.js
import {
UPDATE_PASSWORD_REQUEST,
UPDATE_PASSWORD_SUCCESS,
UPDATE_PASSWORD_FAIL,
CLEAR_ERRORS,
} from "../Constants/userConstant";
export const updatePassword = (passwords) => async (dispatch) => {
try {
dispatch({ type: UPDATE_PASSWORD_REQUEST });
const config = { headers: { "Content-Type": "application/json" } };
const { data } = await axios.put(
`/api/v1/password/update`,
passwords,
config
);
dispatch({ type: UPDATE_PASSWORD_SUCCESS, payload: data.success });
} catch (error) {
dispatch({
type: UPDATE_PASSWORD_FAIL,
payload: error.response.data.message,
});
}
};
export const clearErrors = () => async (dispatch) => {
dispatch({ type: CLEAR_ERRORS });
};
store.js
import {createStore,combineReducers,applyMiddleware} from 'redux';
import thunk from "redux-thunk";
import {composeWithDevTools} from "redux-devtools-extension";
import { profileReducer } from './Reducers/userReducer';
const reducer = combineReducers({
profile:profileReducer,
})
let initialState = {};
const middleware = [thunk];
const store = createStore(
reducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;
UpdatePassword.js
import React, { Fragment, useState, useEffect } from "react";
import "./UpdatePassword.css";
import Loader from "../Loader/Loader";
import { useDispatch, useSelector } from "react-redux";
import { clearErrors, updatePassword } from "../../Actions/userAction";
import { UPDATE_PASSWORD_RESET } from "../../Constants/userConstant";
import {useNavigate} from 'react-router-dom'
const UpdatePassword = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
const { error, isUpdated, loading } = useSelector((state) => state.profile);
const [oldPassword, setOldPassword] = useState("");
const [newPassword, setNewPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const updatePasswordSubmit = (e) => {
e.preventDefault();
const myForm = new FormData();
myForm.set("oldPassword", oldPassword);
myForm.set("newPassword", newPassword);
myForm.set("confirmPassword", confirmPassword);
dispatch(updatePassword(myForm));
};
useEffect(() => {
if (error) {
alert(error);
dispatch(clearErrors());
}
if (isUpdated) {
alert("Profile Updated Successfully");
navigate("/account");
dispatch({
type: UPDATE_PASSWORD_RESET,
});
}
}, [dispatch, error, isUpdated]);
return (
<Fragment>
{loading ? (
<Loader />
) : (
<Fragment>
{/* <MetaData title="Change Password" /> */}
<div className="updatePasswordContainer">
<div className="updatePasswordBox">
<h2 className="updatePasswordHeading">Update Profile</h2>
<form
className="updatePasswordForm"
onSubmit={updatePasswordSubmit}
>
<div className="loginPassword">
<input
type="password"
placeholder="Old Password"
required
value={oldPassword}
onChange={(e) => setOldPassword(e.target.value)}
/>
</div>
<div className="loginPassword">
<input
type="password"
placeholder="New Password"
required
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
/>
</div>
<div className="loginPassword">
<input
type="password"
placeholder="Confirm Password"
required
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
/>
</div>
<input
type="submit"
value="Change"
className="updatePasswordBtn"
/>
</form>
</div>
</div>
</Fragment>
)}
</Fragment>
);
};
export default UpdatePassword;
i want to make a form where user update user password.but due to any mistake this form is not working...
I'm not sure if the problem is in useSelector or in useDispatch hooks or in another place, so here is the scenario:
Two screens (HomeScreen & AddBlogScreen)
In HomeScreen I click add blog button then it redirect to AddBlogScreen
I input the data, then submit. After the submit is success then redirect to HomeScreen
As mentioned in below pic, I got the no 4 result & I have to refresh to get the no 3 result. But my expectation is no 3 pic without getting the error.
Here is my code:
HomeScreen
import jwtDecode from "jwt-decode";
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useHistory } from "react-router";
import { blogList } from "../redux/action";
export const MainScreen = () => {
// const [token, setToken] = useState(localStorage.getItem("token"));
const user = jwtDecode(localStorage.getItem("token"));
const history = useHistory();
const dispatch = useDispatch();
useEffect(() => {
dispatch(blogList());
}, [dispatch]);
const { blog } = useSelector((state) => state.blog);
console.log(blog);
return (
<>
<button
onClick={() => {
localStorage.removeItem("token");
history.push("/");
}}
>
singout
</button>
<button
onClick={() => {
history.push({ pathname: "/Blog", state: user });
}}
>
add blog
</button>
<h1 style={{ color: "red" }}>username: {user.username}</h1>
{blog.map(({ id, b_title, b_content, category_id }) => (
<div key={id}>
<h1
onClick={() =>
history.push({
pathname: "/Edit",
state: { id, b_title, b_content, category_id },
})
}
>
Title: {b_title}
</h1>
<p>Content: {b_content}</p>
</div>
))}
</>
);
};
AddBlogScreen
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { useHistory, useLocation } from "react-router";
import { addBlog } from "../redux/action";
export const AddBlogScreen = () => {
const history = useHistory();
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const [category, setCategory] = useState("");
const dispatch = useDispatch();
const location = useLocation();
const author = location.state.id;
const submitHandler = (e) => {
e.preventDefault();
dispatch(addBlog(title, content, author, category));
setTitle("");
setContent("");
setCategory("");
history.push("/Home");
};
return (
<div>
<h1>add blog page</h1>
<form onSubmit={submitHandler}>
<input
type="text"
placeholder="title"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<br />
<br />
<input
type="text"
placeholder="content"
value={content}
onChange={(e) => setContent(e.target.value)}
/>
<br />
<br />
<input
type="text"
placeholder="category"
value={category}
onChange={(e) => setCategory(e.target.value)}
/>
<br />
<br />
<input
type="submit"
value="submit"
disabled={
title === "" || content === "" || category === "" ? true : false
}
/>
</form>
</div>
);
};
actions
import axios from "axios";
import {
LIST_BLOG,
ADD_BLOG,
EDIT_BLOG,
DELETE_BLOG,
LOGIN_USER,
REGISTER_USER,
LOGOUT_USER,
} from "./constant";
// ==================== blog actions ======================
export const blogList = () => async (dispatch) => {
try {
const result = await axios
.get("http://localhost:3001/api/v1/blog?page=0")
.then((res) => res.data.data)
.catch((err) => err);
dispatch({
type: LIST_BLOG,
payload: result,
});
} catch (err) {
dispatch({
payload: err,
});
}
};
export const addBlog =
(title, content, author, category) => async (dispatch) => {
try {
const result = await axios
.post("http://localhost:3001/api/v1/blog", {
blog_title: title,
blog_content: content,
author_id: author,
category_id: category,
})
.then(alert("success add blog"))
.catch((err) => alert(err));
dispatch({
type: ADD_BLOG,
payload: result,
});
} catch (err) {
dispatch({
payload: err,
});
}
};
reducer
const initial_state = {
blog: [],
};
export const blogReducer = (state = initial_state, action) => {
switch (action.type) {
case LIST_BLOG:
return {
...state,
blog: action.payload,
};
case ADD_BLOG:
return {
...state,
blog: action.payload,
};
case EDIT_BLOG:
return {
...state,
blog: action.payload,
};
case DELETE_BLOG:
return {
...state,
blog: action.payload,
};
default:
return state;
}
};
store
import { blogReducer, userReducer } from "./reducer";
import { combineReducers, createStore, applyMiddleware } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import thunk from "redux-thunk";
const reducer = combineReducers({
blog: blogReducer,
user: userReducer,
});
const middleWare = composeWithDevTools(applyMiddleware(thunk));
export const store = createStore(reducer, middleWare);
First of all, the origin of error:
the error says a property named map on blog is not a function, meaning blog is not an array.
This is where it is coming from:
const { blog } = useSelector((state) => state.blog);
Your state is a an ojbect with a property named blog, you can access it these two ways:
const { blog } = useSelector((state) => state);
or
const blog = useSelector((state) => state.blog);
Other issues I noticed :
in addBlog:
1. When you are using try-catch with await, it's not a good idea to use then-catch too.
2.result won't be the blog data you expect. It will be an object, which is an instance of AxiosResponse, which includes the data.
you can extract the data from response object this way:
let response = await axios.post(... // some api request
let {data}=response
I would edit it like this:
export const addBlog =
(title, content, author, category) => async (dispatch) => {
try {
const {data} = await axios
.post("http://localhost:3001/api/v1/blog", {
blog_title: title,
blog_content: content,
author_id: author,
category_id: category,
})
alert("success add blog")
dispatch({
type: ADD_BLOG,
payload: data,
});
} catch (err) {
dispatch({
payload: err,
});
}
};
I found the solution, so in my action I changed it into:
dispatch({
type: LIST_BLOG,
payload: result.data.data,
});
I have a form that adds new articles. I need to create another form that triggers when I click on a created article and add a property "keyword" to the article state and display it. I tried to do something but I am kinda stuck.
Form.jsx component that adds the article/s:
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { v1 as uuidv1 } from 'uuid';
import { ADD_ARTICLE } from '../constants/action-types';
const Form = () => {
const [title, setTitle] = useState('');
const dispatch = useDispatch();
const handleChange = (e) => {
const { value } = e.target
setTitle(value);
}
const handleSubmit = (e) => {
e.preventDefault();
const id = uuidv1();
dispatch({ type: ADD_ARTICLE, payload: { id, title } });
setTitle('');
}
return (
<form onSubmit={handleSubmit}>
<div className='form-group'>
<label htmlFor='title'>Title</label>
<input
type='text'
className='form-control'
id='title'
value={title}
onChange={handleChange}
/>
</div>
<input className='btn btn-success btn-lg' type='submit' value='SAVE' />
</form>
);
}
export default Form;
List.jsx component where the articles are displayed:
import React, { useState,useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import KeywordForm from './KeywordForm.jsx';
import { fetchArticles } from '../thunk';
const List = () => {
const [showForm,setShowForm]=useState(false);
const articles = useSelector(state => state.articles);
const dispatch = useDispatch();
const displayForm=()=>{
setShowForm(!showForm)
}
useEffect(() => {
dispatch(fetchArticles);
}, []);
return (
<>
<ul className='list-group list-group-flush'>
{articles.map(article => (
<li className='list-group-item' key={article.id} onClick={displayForm}>
{article.title}
</li>
))}
</ul>
<div>
{showForm && (
<KeywordForm />
)}
</div>
</>
);
}
export default List;
Here i added a state that displays the KeywordForm component when I click an article.
KeywordForm.jsx component,this is the one that I created to add the keyword:
import React, { useState } from 'react';
import { useDispatch ,useSelector} from 'react-redux';
import { ADD_KEYWORD } from '../constants/action-types';
const KeywordForm = ({id,title}) => {
const [keyword,setKeyword]=useState('');
const articles = useSelector(state => state.articles);
const dispatch=useDispatch();
console.log(articles)
const handleChange = (e) => {
const { value } = e.target
setKeyword(value);
}
const handleSubmit = (e) => {
e.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<div className='form-group'>
<label htmlFor='keyword'>Keyword</label>
<input
type='text'
className='form-control'
id='keyword'
value={keyword}
onChange={handleChange}
/>
</div>
<input className='btn btn-success btn-lg' type='submit' value='SAVE' />
</form>
);
}
export default KeywordForm;
reducers.js
const initialState = {
articles: []
};
const rootReducer = (state = initialState, action) => {
const { type, payload } = action;
switch(type) {
case ADD_ARTICLE: {
return {...state,
articles: [...state.articles,payload]
};
}
case ADD_KEYWORD: {
return Object.assign({}, state, {
articles: state.articles.concat(payload)
});
}
case ARTICLES_RETRIEVED: {
return Object.assign({}, state, {
articles: state.articles.concat(payload)
});
}
default:
return state;
}
}
export default rootReducer;
actions.js
import { ADD_ARTICLE, ARTICLES_RETRIEVED,ADD_KEYWORD } from '../constants/action-types';
const addArticle = (payload) => {
return { type: ADD_ARTICLE, payload };
}
const addKeyword = (payload) => {
return { type: ADD_KEYWORD, payload };
}
const articlesRetrieved = (payload) => {
return { type: ARTICLES_RETRIEVED, payload };
}
export { addArticle, articlesRetrieved,addKeyword };
What should i add to my reducers/actions to make this work? My idea is that i have to somehow pass the id of the article clicked and then in the reducer find it's index or something and check it with the payload.id .
You want to modify an existing article in the state and a keyword to it (can there be an array of keywords, or just one?). In order to do that, your action payload will need to contain both the keyword and the id of the article that it belongs to.
Your reducer will find the article that matches the id and replace it with a copied version that has the keyword added to it.
case ADD_KEYWORD: {
return {
...state,
articles: state.articles.map(article =>
// find the article to update
article.id === payload.id ?
// update it
{ ...article, keyword: payload.keyword } :
// otherwise return the original
article
}
}
This is easier to do with the official Redux Toolkit because you can modify the draft state directly and you don't need to worry about mutations.
I'm trying to write a test and I'm not getting the result thats its intended, can someone see what I'm doing wrong here please? I'm trying to call my addTodo but all I get is the error message below, quite new to testing so I'm not sure what it means.
my error message is this:
● <TodoForm /> #addTodo
expect(jest.fn()).toBeCalledWith(...expected)
Expected: {"payload": "a new todo", "type": "addTodo"}
Number of calls: 0
24 | form.find("button").simulate("click");
25 |
> 26 | expect(dispatch).toBeCalledWith({ type: "addTodo", payload: "a new todo" });
| ^
27 | });
28 |
at Object.<anonymous> (src/tests/TodoForm.test.js:26:20)
Here the relevant files:
the test: TodoForm.test.js
import React from "react";
import Enzyme, { mount } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import { Provider } from "../context/TodoContext";
import TodoForm from "../components/TodoForm";
Enzyme.configure({ adapter: new Adapter() });
test("<TodoForm /> #addTodo", async () => {
const dispatch = jest.fn();
const form = mount(
<Provider value={{ dispatch }}>
<TodoForm />
</Provider>
);
form.find("input").simulate("change", { target: { value: "a new todo" } });
form.find("button").simulate("click");
expect(dispatch).toBeCalledWith({ type: "addTodo", payload: "a new todo" });
});
the file I'm trying to write the test for:
import React, { useContext, useState } from "react";
import { Context } from "../context/TodoContext";
import "../css/TodoForm.css";
const TodoForm = ({ initialValues }) => {
const { addTodo } = useContext(Context);
const [title, setTitle] = useState("");
const [error, setError] = useState("");
function handleTodoAdd() {
if (title === "") {
setError(true);
} else {
setError(false);
}
setTitle("");
}
const onChange = e => {
setTitle(e.target.value);
};
/*
function handleSubmitForm(event) {
if (event.keyCode === 13) handleTodoAdd();
}
*/
return (
<div className="container">
<div className="inputContainer">
<div className="input-group">
<input
autoFocus={true}
aria-label="Enter the title of your todo"
placeholder="Enter new todo"
value={title}
onChange={onChange}
/>
<div className="errorContainer">
<span className="error">
{error ? "Please enter a value" : null}
</span>
</div>
<div className="input-group-append">
<button
aria-label="Add todo to your list"
className="addButton"
onClick={() => addTodo(title)}
>
Add
</button>
</div>
</div>
</div>
</div>
);
};
TodoForm.defaultProps = {
initialValues: {
title: "adsda"
}
};
export default TodoForm;
TodoContext.js I'm using this file to pull my provider
import React from "react";
import createDataContext from "./createDataContext";
export const TodoContext = React.createContext();
export default function todoReducer(state, action) {
switch (action.type) {
case "addTodo":
return [
...state,
{ id: Math.floor(Math.random() * 999), title: action.payload }
];
case "deleteTodo":
return state.filter(todo => todo.id !== action.payload);
case "editTodo":
return state.map(todo => {
return todo.id === action.payload.id ? action.payload : todo;
});
default:
return state;
}
}
const addTodo = dispatch => {
return title => {
dispatch({ type: "addTodo", payload: title });
};
};
const deleteTodo = dispatch => {
return id => {
dispatch({ type: "deleteTodo", payload: id });
};
};
const editTodo = dispatch => {
return (id, title) => {
dispatch({ type: "editTodo", payload: { id, title } });
};
};
export const { Context, Provider } = createDataContext(
todoReducer,
{ addTodo, deleteTodo, editTodo },
[]
);
auto creates my context data
import React, { useReducer } from "react";
export default (reducer, actions, initialState) => {
const Context = React.createContext();
const Provider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
const boundActions = {};
for (let key in actions) {
boundActions[key] = actions[key](dispatch);
}
return (
<Context.Provider value={{ state, ...boundActions }}>
{children}
</Context.Provider>
);
};
return { Context, Provider };
};
I need your help. I'm creating an app with useContext and useReducer hooks and I a have problems. I have a function to get all notes from my database. I called that function inside off useEffect hook:
import React, { useContext, useEffect } from "react";
import { useTranslation } from "react-i18next";
//Context
import AuthContext from "../../context/auth/authContext";
import NoteContext from '../../context/notes/noteContext';
//Components
import { Row, Col, Container, Button } from "react-bootstrap";
import Canva from '../Canva/Canva';
import Note from '../Note/Note';
const Dashboard = () => {
const { t, i18n } = useTranslation();
const authContext = useContext(AuthContext);
const { authUser, user } = authContext;
const noteContext = useContext(NoteContext);
const { notes, getNotes, addNote } = noteContext;
useEffect(() => {
getNotes();
}, []);
return (
<>
<Container>
<Row>
<Col sm={12} md={10}>
<Button onClick={() => addNote()} type='button' className='mb-2'>
Añadir elemento
</Button>
<Canva>
{notes && (notes.map(note => {
return (
<Note key={note._id} note={note} />
)
}))}
</Canva>
</Col>
</Row>
</Container>
</>
);
};
export default Dashboard;
If I called that function that way, my state doesn't change:
notes: undefined
But if I introduce a dependency inside of useEffect, my app goes into an infinite loop. For example:
useEffect(() => {
getNotes();
}, [notes])
//Or:
useEffect(() => {
getNotes()
}, [getNotes])
How can I avoid the infinite loop?
You need to use 2 useEffect hooks, one for fetch data and second to proceed it:
useEffect(() => {
getNotes();
}, []);
useEffect(() => {
if (notes && notes.length) {
....setState or what else
}
}, [notes]);
My note state looks like:
import React, { useReducer } from 'react';
import clientAxios from '../../config/clientAxios';
import NoteContext from './noteContext';
import NoteReducer from './noteReducer';
import {
GET_NOTES,
ADD_NOTE,
DELETE_NOTE,
UPDATE_NOTE,
} from '../../types';
const NoteState = ({ children }) => {
const initialState = {
notes: [],
noteError: false,
};
const [state, dispatch] = useReducer(NoteReducer, initialState);
const getNotes = async () => {
try {
const response = await clientAxios.get('/user/Notes');
dispatch({
type: GET_NOTES,
payload: response.data
})
} catch (error) {
console.log(error.response);
}
}
const addNote = async data => {
try {
const response = await clientAxios.post('/addNote', data);
dispatch({
type: ADD_NOTE,
payload: response.data.data
})
} catch (error) {
console.log(error.response);
}
}
const updateNote = async (id, { title, description }) => {
try {
const response = await clientAxios.put(`updateNote/${id}`, { title, description });
console.log(response.data);
dispatch({
type: UPDATE_NOTE,
payload: response.data
})
} catch (error) {
console.log(error.response)
}
}
const deleteNote = async id => {
try {
await clientAxios.put(`/deleteNote/${id}`);
dispatch({
type: DELETE_NOTE,
payload: id
})
} catch (error) {
console.log(error.response);
}
}
return(
<NoteContext.Provider
value={{
notes: state.notes,
noteError: state.noteError,
getNotes,
addNote,
updateNote,
deleteNote,
}}
>
{children}
</NoteContext.Provider>
);
}
export default NoteState;
and my reducer:
import {
GET_NOTES,
ADD_NOTE,
DELETE_NOTE,
UPDATE_NOTE,
} from '../../types';
export default (action, state) => {
switch(action.type) {
case GET_NOTES:
return {
...state,
notes: action.payload
}
case ADD_NOTE:
return {
...state,
notes: [...state.notes, action.payload]
}
case UPDATE_NOTE:
return {
...state,
notes: state.notes.map(note => note._id === action.payload._id ? action.payload : note)
}
case DELETE_NOTE:
return {
...state,
notes: state.notes.filter(note => note._id !== action.payload),
}
default:
return state;
}
}