Why is my prop returning undefined? I'm trying to access 'total', but its undefined. I pass it in as a prop but it logs to the console as undefined and its also returning blank on the page. I think I might be making a mistake somewhere, because I have done it this way before and it worked.
Here is my container Store.js
import { connect } from 'react-redux';
import { getItems, getCurrency, getTotal} from '../ducks/cart';
import Store from '../components/Store';
const mapStateToProps = (state, props) => {
return {
total: getTotal(state, props)
}
}
export default connect(mapStateToProps)(Store);
Here is my Store.js component:
import React, {Component} from 'react';
import { PropTypes } from 'react';
import Home from '../components/Home';
import Cart from '../containers/Cart';
import ProductList from '../containers/ProductList';
import Checkout from '../containers/Checkout';
const Store = ({ total }) => {
console.error(total);
return(
<div className="container">
<div className="row">
<div className="col-md-12">
<h3>Armor and Weapon Store</h3>
<h4 className="badge badge-warning margin-right">Gold: {total} </h4>
</div>
</div>
<div className="row">
<div className="col-md-8">
<ProductList />
</div>
<div className="col-md-4">
<Cart />
<Checkout />
</div>
</div>
</div>
);
}
Store.propTypes = {
total: PropTypes.number,
}
export default Store;
And here is my redux stuff Cart.js:
import { getProduct } from '../ducks/products';
// actions
const CART_ADD = 'cart/ADD';
const CART_REMOVE = 'cart/REMOVE';
// reducer
const initialState = {
items: [], // array of product ids
currency: 'GOLD'
};
export default function cart(state = initialState, action = {}) {
switch (action.type) {
case CART_ADD:
return handleCartAdd(state, action.payload);
case CART_REMOVE:
return handleCartRemove(state, action.payload);
default:
return state;
}
}
function handleCartAdd(state, payload) {
return {
...state,
items: [ ...state.items, payload.productId ]
};
}
function handleCartRemove(state, payload) {
return {
...state,
items: state.items.filter(id => id !== payload.productId)
};
}
// action creators
export function addToCart(productId) {
return {
type: CART_ADD,
payload: {
productId
}
}
}
export function removeFromCart(productId) {
return {
type: CART_REMOVE,
payload: {
productId
}
}
}
// selectors
export function isInCart(state, props) {
return state.cart.items.indexOf(props.id) !== -1;
}
export function getItems(state, props) {
return state.cart.items.map(id => getProduct(state, { id }));
}
export function getCurrency(state, props) {
return state.cart.currency;
}
export function getTotal(state, props) {
return state.cart.items.reduce((acc, id) => {
const item = getProduct(state, { id });
const total = acc + item.price;
return acc + item.price;
}, 0);
}
Related
I don't know what is happening with the component im trying to map an array of objects from mongo here but it is no showing nothing to printInventory, but if i call to this.props.inventory and it takes all the data! What is happening?
printInventory = () => {
this.props.inventory.map((inventory) => {
return (
<CardInventario
cardTitle={inventory.name}
quantity={inventory.quantity}
description={inventory.price}
/>
)
})
}
in these function.
Next I going to show the actions and the reducers:
inventoryReducer:
import {TAKE_INVENTORY} from '../../types/inventoryTypes';
const INITIAL_STATE ={
inventory: []
}
function invetoryReducer(state = INITIAL_STATE,action){
switch (action.type) {
case TAKE_INVENTORY:
return {...state, inventory: action.payload}
break;
default:
return state;
break;
}
}
export default invetoryReducer;
and here is the inventoryActions:
import axios from 'axios'
import { TAKE_INVENTORY } from '../../types/inventoryTypes'
export const takeInventory = () => async (dispatch) =>{
const res = await axios.get('http://localhost:3001/inventory')
dispatch({
type: TAKE_INVENTORY,
payload: res.data
})
}
And the full component:
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import axios from 'axios'
/* Components and Styles */
import CardInventario from '../components/CardInventario'
import '../assets/styles/container/Stock.scss'
/* Redux */
import * as inventoryActions from '../actions/inventoryActions'
class Stock extends Component {
componentDidMount() {
this.props.takeInventory();
}
printInventory = () => {
this.props.inventory.map((inventory) => {
return (
<CardInventario
cardTitle={inventory.name}
quantity={inventory.quantity}
description={inventory.price}
/>
)
})
}
render() {
console.log(this.props.inventory)
return (
<>
<div className="container">
<div className="additem">
<Link to="/additem" className="additem__link">
<p className="link-add">
AƱadir Item a Stock
</p>
</Link>
</div>
<div className="stock" key="stock">
{this.printInventory()}
</div>
</div>
</>
)
}
}
const mapStateToProps = (reducers) => {
return reducers.inventoryReducer;
}
export default connect(mapStateToProps, inventoryActions)(Stock);
First of all, please use the correct mapping.
inventoryReducer is not the one you're looking to map.
inventory inside that object is the one you want.
const mapStateToProps = (reducers) => {
return reducers.inventoryReducer.inventory;
}
Also if you get data in this.props.inventory, it should be related to duplicated keys
Please try the following
printInventory = () => {
this.props.inventory.map((inventory, index) => {
return (
<CardInventario
key={index}
cardTitle={inventory.name}
quantity={inventory.quantity}
description={inventory.price}
/>
)
})
}
If you don't have id, it is possible to use index instead (not recommended though)
printInventory = () => {
this.props.inventory.map((inventory) => {
return (
<CardInventario
key={inventory.id}
cardTitle={inventory.name}
quantity={inventory.quantity}
description={inventory.price}
/>
)
})
}
I am trying to load a store asynchronously but getting errors. I am trying to do this as wish to ultimately lazy-load the store due to heavy firebase/firestore middleware, 400kb+. If I can get this test to work, i would then import dynamically. However, it seems like that the provider doesn't like this. Can anyone suggest a work around? I have created a Pen to illustrate https://codepen.io/Haalix/pen/ZEYPrmG?editors=1111
HTML:
div#root
JS:
const thunk = ReduxThunk.default
const { Provider, connect } = ReactRedux
const { createStore, applyMiddleware } = Redux
class App extends React.Component {
handleAdd = () => {
this.props.addValueLazy()
}
handleCut = () => {
this.props.cutValue()
}
render() {
const { value } = this.props
return (
<div className="wrapper">
<h1 className="title">Counter</h1>
<Counter
value={value}
onAdd={this.handleAdd}
onCut={this.handleCut}
/>
</div>
)
}
}
const Counter = ({ value, onAdd, onCut }) => (
<section className="count-container">
<div className="value">{value}</div>
<div className="buttonGroup">
<button onClick={onAdd}>LAZY ADD</button>
<button onClick={onCut}>CUT</button>
</div>
</section>
)
const ActionTypes = {
ADD_VALUE: 'ADD_VALUE',
CUT_VALUE: 'CUT_VALUE'
}
function mapDispatchToProps(dispatch) {
return {
addValueLazy: () => dispatch(addValueLazy()),
cutValue: () => dispatch(cutValue()),
dispatch
}
}
function mapStateToProps(state) {
return {
value: state.value
}
}
const initialState = { value: 0 }
function counterReducer(state = initialState, action) {
switch(action.type) {
case ActionTypes.ADD_VALUE:
return {
value: state.value + 1
}
case ActionTypes.CUT_VALUE:
return {
value: state.value - 1
}
default:
return state;
}
}
function addValueLazy() {
return function(dispatch) {
return setTimeout(()=>dispatch(addValue()), 300)
}
}
function addValue() {
return {
type: ActionTypes.ADD_VALUE
}
}
function cutValue() {
return {
type: ActionTypes.CUT_VALUE
}
}
const AppWithState = connect(mapStateToProps, mapDispatchToProps)(App)
async function storeMaker() {
return await createStore(counterReducer, initialState,
applyMiddleware(thunk)
)
}
const store = storeMaker();
const Root = () => (
<Provider store={store}>
<AppWithState />
</Provider>
)
ReactDOM.render(
<Root />,
document.querySelector('#root'),
)
I'm trying to do some react/redux basics here, but have the problem that the change in state inside the state store isn't reflected in component UI. here is my code, what wrong did I made?
projectReducer.js
Here is the reducer:
const initState = {
projects: [],
};
const projectReducer = (state = initState, action) => {
switch (action.type) {
case CREATE_PROJECT:
const project = action.project;
state.projects.unshift(project);
return {
...state
};
case GET_PROJECTS:
state.projects = action.projects;
return {
...state
};
default:
break;
}
return state;
}
export default projectReducer
projectAction.js
Here is the action
import axios from 'axios';
export const createProjectActionCreator = project => {
return (dispatch, getState) => {
// make async call to dispatch
axios.post('http://localhost:4000/projects/create-project', project).then(result => {
dispatch({
type: 'CREATE_PROJECT',
project: result.data.project
});
}).catch(err => {
console.log(err)
});
}
}
export const getProjectsActionsCreator = () => {
return (dispatch, getState) => {
axios.get("http://localhost:4000/projects").then(result => {
dispatch({
type: 'GET_PROJECTS',
projects: result.data.projects
});
}).catch(err => {
console.log(err)
});
};
}
createProjectComponent.js
Here is compnent has create project form
import React from 'react';
import { connect } from "react-redux";
import { createProjectActionCreator } from "../../store/actions/projectActions";
class CreateProject extends React.Component {
state = {
projectData: {
title: '',
content: ''
},
createProjectErrors: []
}
handleChange = e => {
const { id, value } = e.target;
const { projectData } = this.state;
projectData[id] = value;
this.setState({projectData});
}
handleSubmit = (e) => {
e.preventDefault();
this.props.createProject(this.state.projectData);
}
render() {
return (
<div className="container">
<form onSubmit={e => this.handleSubmit(e)} className="white">
<h5 className="grey-text text-darken-3">Create New Project</h5>
<div className="input-field">
<label htmlFor="title">Title</label>
<input type="text" id="title" onChange={e => this.handleChange(e)}/>
</div>
<div className="input-field">
<label htmlFor="content">Content</label>
<textarea className="materialize-textarea" id="content" onChange={e => this.handleChange(e)}></textarea>
</div>
<div className="input-field">
<button className="btn pink lighten-1 z-depth-0">Create Project</button>
</div>
</form>
</div>
)
}
}
const mapDispatchToProps = dispatch => {
return {
createProject: project => dispatch(createProjectActionCreator(project))
}
}
export default connect(null, mapDispatchToProps)(CreateProject)
Dashboard.js
This component act like home page which renders project list and the form of project creation
import React, { Component } from 'react';
// import Notifications from './Notifications';
import ProjectList from '../projects/PorjectList';
import { connect } from 'react-redux';
import CreateProject from '../projects/CreateProject';
import { getProjectsActionsCreator } from "../../store/actions/projectActions";
class Dashoard extends Component {
componentWillMount() {
this.props.fetchProjects();
}
render() {
return (
<div className="dashboard container">
<div className="row">
<div className="col s12 m6">
<ProjectList projects={this.props.projects} />
</div>
<div className="col s12 m6">
<CreateProject />
</div>
</div>
</div>
)
}
}
const mapStateToProps = state => {
console.log(state.project);
return {
projects: state.project.projects
}
}
const mapDispatchToProps = dispatch => {
return {
fetchProjects: () => dispatch(getProjectsActionsCreator())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Dashoard)
[enter image description here][1]
The problem is in your reducer, you shouldn't mutate state (See the Redux docs on immutability).
const projectReducer = (state = initState, action) => {
switch (action.type) {
case CREATE_PROJECT:
const project = action.project;
state.projects.unshift(project);
return {
...state
};
case GET_PROJECTS:
state.projects = action.projects;
return {
...state
};
default:
break;
}
return state;
}
In each of your cases you are returning a referentially different copy of state, but you're mutating the original state first. Here's how you want to do it instead:
const projectReducer = (state = initState, action) => {
switch (action.type) {
case CREATE_PROJECT:
return {
...state, projects: [action.project, ...state.projects]
};
case GET_PROJECTS:
return {
...state, projects: action.projects
};
default:
return state;
}
}
Note that ...state isn't strictly necessary in this case, since projects is your only state (and you want to overwrite it), but if you add more state, you'll need to spread state to avoid overwriting any other state in the store.
I am new to to redux and react. Still doing simple tutorials. I managed to create 2 simple components; one that outputs on the screen (as a list) whatever is in the array in the redux store, and the other component contains a button and a textfield which basically adds to that array in the store.
I would like to add a feature that will enable me to delete a specific entry in the list depending on what the user clicked on. I am thinking of creating a <button> next to each <li> tag that gets rendered as it loops through the array, and these buttons will correspond to the respective list elements. But I'm not sure how to do that.
I've tried creating a button when each <li> tag gets created but I was getting an error on the console stating that each element in a list needs a unique ID. I then decided to create another array in my store called buttons which will contain a unique id as well as the id of the list but it got out of hand. I think I might be overcomplicating this. This is what I have at the moment:
Components:
List.jsx (responsible for outputting the list)
import React from 'react'
import { connect } from "react-redux";
const ListComp = ({ lists }) => (
<div>
<ul>
{console.log(lists)}
{lists.map( element => (
<li key={element.id}>
{element.titleToBeAddedToList}
</li>
))}
</ul>
</div>
)
const mapStateToProps = state => {
return {
lists: state.lists
};
}
const List = connect(mapStateToProps)(ListComp)
export default List;
SubmitButton.jsx (responsible for outputting the button and textfield)
import React from 'react'
import { connect } from "react-redux";
import uuidv1 from "uuid";
import { addList } from "../actions/index";
import { addButton } from "../actions/index"
function mapDispatchToProps(dispatch){
return {
addlist: article => dispatch(addList(article)),
addbutton: idOfButton => dispatch(addButton(idOfButton))
};
}
class Submit extends React.Component{
constructor(){
super();
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ [event.target.id]: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
const {titleToBeAddedToList} = this.state;
const id = uuidv1();
const button_id = uuidv1();
//Dispatching the action:
this.props.addlist({ titleToBeAddedToList, id });
this.props.addbutton({id, button_id});
//Once we've dispatched an action, we want to clear the state:
this.setState({ titleToBeAddedToList: "" });
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="title">Title</label>
<input
type="text"
className="form-control"
id="titleToBeAddedToList"
onChange={this.handleChange}
/>
</div>
<button type="submit" className="btn btn-success btn-lg">
SAVE
</button>
</form>
);
}
}
const SubmitButton = connect(null, mapDispatchToProps)(Submit)
export default SubmitButton;
Reducers:
const initialState = {
lists: [],
buttons: []
};
function rootReducer (state = initialState, action) {
if(action.type === "ADD_LIST" ){
return Object.assign({}, state, {
lists: state.lists.concat(action.payload)
});
} else if(action.type === "ADD_BUTTON"){
return Object.assign({}, state, {
buttons: state.lists.concat(action.payload)
});
} else if(action.type === "DELETE_FROM_LIST"){
//.....//
}
return state;
}
export default rootReducer;
Action:
export function addList(payload) {
return { type: "ADD_LIST", payload }
};
export function addButton(payload){
return {type: "ADD_BUTTON", payload }
}
export function deleteList(payload){
return { type: "DELETE_FROM_LIST", payload }
}
Store:
import { createStore } from "redux";
import rootReducer from "../reducers/index";
const store = createStore(rootReducer);
export default store;
You can use Math.random() as an unique key identifier, if the button is click it will call action deleteItem with the ID, action is bound to reducer pass on the ID, you can then use the ID to indentify elements and remove it in the list.
import React from 'react'
import { connect } from "react-redux";
import { deleteItem } from './actions';
const ListComp = ({ lists }) => (
<div>
<ul>
{console.log(lists)}
{lists.map( element => (
<li key={Math.random()} key={element.id}>
{element.titleToBeAddedToList}
<button onClick={() => deleteItem(element.id)}>X</button>
</li>
))}
</ul>
</div>
)
const mapStateToProps = state => {
return {
lists: state.lists
};
}
const List = connect(mapStateToProps, {deleteItem})(ListComp) // Make it available to component as props
export default List;
Action:
export function deleteElement(id) {
return function(dispatch) {
return dispatch({type: "DELETE_FROM_LIST", payload: id})
}
}
Reducer:
case 'DELETE_FROM_LIST': {
const id = action.payload;
return {
...state,
list: state.list.filter(item => item.id !== id)
}
}
else if (action.type === "DELETE_FROM_LIST") {
return Object.assign({}, state, {
buttons: state.lists.filter(item => (item.id !==action.payload))
});
}
you can use filter() for delete.
This is a minimal working react-redux example containing all the pieces to delete an item from an array in redux store.
// reducer.js
const reducer = (state, action) => {
switch (action.type) {
case 'DELETE':
return state.filter(item => (
item.id !== action.payload.id
))
default: return state;
}
}
// Item.js
const Item = ({id, onClick, label}) => (
<li>
{label}
<button onClick={ () => onClick(id) }>
delete
</button>
</li>
)
// ListContainer.js
const mapStateToProps = state => ({ items: state })
const ListContainer = ReactRedux.connect(mapStateToProps)(class extends React.Component {
handleDelete = id => {
const { dispatch } = this.props;
dispatch({ type: 'DELETE', payload: { id } })
}
render() {
const { items } = this.props;
return items.map(({id, label}) => (
<Item
label={label}
id={id}
onClick={this.handleDelete}
/>
))
}
})
// Main.js
const initialState = [
{ id: 1, label: 'item 1' },
{ id: 2, label: 'item 2' },
{ id: 3, label: 'item 3' },
{ id: 4, label: 'item 4' }
]
const store = Redux.createStore(reducer, initialState);
class App extends React.Component {
render(){
return (
<ReactRedux.Provider store={store}>
<ListContainer />
</ReactRedux.Provider>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.1/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/6.0.1/react-redux.js"></script>
<div id="root"></div>
all I am fairly new to React, and Redux and have been stuck with this issue for an entire day now. The data is dispatching from my component to my action creator, then to my reducer, and the state is being updated. However, when I change inputs and begin typing, it clears all other data in the form except for the data of the input I am currently typing in. If I take out the spread operator, the data then stays, but from every tutorial, I have seen this should not happen. Am I doing something wrong?
AddProject.js (form component)
import React, { useEffect } from "react";
import styles from "./AddProjects.module.css";
import { connect } from "react-redux";
import {
validateProjectId,
validateProjectDescription,
validateProjectName,
projectStartDate,
projectEndDate,
submitHandler
} from "../../Redux/createProject/action";
const AddProject = props => {
// useEffect(() => {
// console.log("aaa", props);
// }, [props]);
return (
<div className={styles.addProjectContainer}>
<h5>Create / Edit Project form</h5>
<hr />
<form>
<div>
<input
defaultValue=""
type="text"
placeholder="Project Name"
name="projectName"
style={
props.form.projectNameError
? { backgroundColor: "#F08080", opacity: "0.8" }
: { backgroundColor: "white" }
}
onChange={e => props.validateProjectName(e.target.value)}
/>
</div>
<div>
<input
type="text"
placeholder="Unique Project ID"
name="projectIdentifier"
value={props.form.projectIdentifier}
style={
props.form.projectIdentifierError
? { backgroundColor: "#F08080", opacity: "0.8" }
: { backgroundColor: "white" }
}
onChange={e => props.validateProjectId(e.target.value)}
/>
</div>
<div>
<textarea
placeholder="Project Description"
name="description"
value={props.form.description}
style={
props.form.descriptionError
? { backgroundColor: "#F08080", opacity: "0.8" }
: { backgroundColor: "white" }
}
onChange={e => props.validateProjectDescription(e.target.value)}
/>
</div>
<h6>Start Date</h6>
<div>
<input
type="date"
name="start_date"
value={props.form.start_date}
onChange={e => props.projectStartDate(e.target.value)}
/>
</div>
<h6>Estimated End Date</h6>
<div>
<input
type="date"
name="end_date"
value={props.form.end_date}
onChange={e => props.projectEndDate(e.target.value)}
/>
</div>
<button type="button" onClick={props.submitHandler}>
<span>Submit</span>
</button>
</form>
</div>
);
};
//state.form.projectName
const mapStateToProps = state => {
console.log(state.project);
return {
form: state.project
};
};
const mapDispatchToProps = dispatch => {
return {
validateProjectName: payload => dispatch(validateProjectName(payload)),
validateProjectId: payload => dispatch(validateProjectId(payload)),
validateProjectDescription: payload =>
dispatch(validateProjectDescription(payload)),
projectStartDate: payload => dispatch(projectStartDate(payload)),
projectEndDate: payload => dispatch(projectEndDate(payload)),
submitHandler: () => dispatch(submitHandler())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(AddProject);
action.js (action creator)
import {
PROJECT_NAME_CHANGE,
PROJECT_IDENTIFIER_CHANGE,
PROJECT_DESCRIPTION_CHANGE,
START_DATE_CHANGE,
END_DATE_CHANGE,
SUBMIT_HANDLER,
PROJECT_NAME_ERROR,
PROJECT_IDENTIFIER_ERROR,
PROJECT_DESCRIPTION_ERROR
} from "./constants";
export const projectNameChange = projectName => {
return {
type: PROJECT_NAME_CHANGE,
projectName
};
};
export const projectNameError = () => {
return {
type: PROJECT_NAME_ERROR
};
};
export const projectIdChange = projectIdentifier => {
return {
type: PROJECT_IDENTIFIER_CHANGE,
projectIdentifier
};
};
export const projectIdError = () => {
return {
type: PROJECT_IDENTIFIER_ERROR
};
};
export const projectDescriptionChange = description => {
return {
type: PROJECT_DESCRIPTION_CHANGE,
description
};
};
export const projectDescriptionError = () => {
return {
type: PROJECT_DESCRIPTION_ERROR
};
};
export const projectStartDate = start_date => {
return {
type: START_DATE_CHANGE,
start_date
};
};
export const projectEndDate = end_date => {
return {
type: END_DATE_CHANGE,
end_date
};
};
export const submitHandler = () => {
return {
type: SUBMIT_HANDLER
};
};
export function validateProjectName(payload) {
return (dispatch, getState) => {
if (payload.length <= 30) {
dispatch(projectNameChange(payload));
} else {
dispatch(projectNameError());
}
};
}
export function validateProjectId(payload) {
return (dispatch, getState) => {
if (payload.length < 6) {
dispatch(projectIdChange(payload));
} else {
dispatch(projectIdError());
}
};
}
export function validateProjectDescription(payload) {
return (dispatch, getState) => {
if (payload.length < 256) {
dispatch(projectDescriptionChange(payload));
} else {
dispatch(projectDescriptionError());
}
};
}
// thunk call passed project name
// validateProjectName(name){
// if(name.length>4 && ){
// dispatchEvent(setName)
// }
// else{
// dispatch(setNameError)
// }
// }
index.js (Reducer)
PROJECT_NAME_CHANGE,
PROJECT_IDENTIFIER_CHANGE,
PROJECT_DESCRIPTION_CHANGE,
START_DATE_CHANGE,
END_DATE_CHANGE,
SUBMIT_HANDLER,
PROJECT_NAME_ERROR,
PROJECT_IDENTIFIER_ERROR,
PROJECT_DESCRIPTION_ERROR
} from "./constants";
const initialState = {
projectName: "",
projectIdentifier: "",
description: "",
start_date: "",
end_date: "",
projectNameError: false,
projectIdentifierError: false,
descriptionError: false
};
const createProjectReducer = (state = initialState, action) => {
switch (action.type) {
case PROJECT_NAME_CHANGE:
// console.log("We changed project name!", state.projectName, action);
return {
...state,
projectName: action.projectName
};
case PROJECT_IDENTIFIER_CHANGE:
// console.log("We changed project id!", state, action.projectIdentifier);
return {
...state,
projectIdentifier: action.projectIdentifier,
projectIdentifierError: false
};
case PROJECT_DESCRIPTION_CHANGE:
// console.log("We changed project description", state, action.description);
return { ...state, description: action.description };
case START_DATE_CHANGE:
// console.log("We changed the start date", state, action.payload);
return { ...state, start_date: action.payload };
case END_DATE_CHANGE:
// console.log("We changed the end date", state, action.payload);
return { ...state, end_date: action.payload };
case PROJECT_NAME_ERROR:
// console.log("There was an error with the project name!", state);
return { ...state, projectNameError: true };
case PROJECT_IDENTIFIER_ERROR:
// console.log("There was an error with the project Id!", state);
return { projectIdentifierError: true };
case PROJECT_DESCRIPTION_ERROR:
// console.log("There was an error with the project description!", state);
return { ...state, descriptionError: true };
case SUBMIT_HANDLER:
console.log("We submitted yayy", state);
return initialState;
//const formData = state;
//console.log(formData);
default:
return state;
}
};
export default createProjectReducer;
constants.js
export const PROJECT_IDENTIFIER_CHANGE = "PROJECT_IDENTIFIER_CHANGE";
export const PROJECT_DESCRIPTION_CHANGE = "PROJECT_DESCRIPTION_CHANGE";
export const START_DATE_CHANGE = "START_DATE_CHANGE";
export const END_DATE_CHANGE = "END_DATE_CHANGE";
export const SUBMIT_HANDLER = "SUBMIT_HANDLER";
export const PROJECT_NAME_ERROR = "PROJECT_NAME_ERROR";
export const PROJECT_IDENTIFIER_ERROR = "PROJECT_IDENTIFIER_ERROR";
export const PROJECT_DESCRIPTION_ERROR = "PROJECT_DESCRIPTION_ERROR";
rootReducer.js
const rootReducer = (state = {}, action) => {
return {
project: createProjectReducer(state.createProject, action)
};
};
export default rootReducer;
index.js (store creator)
import ReactDOM from "react-dom";
import { createStore, compose, applyMiddleware } from "redux";
import { Provider } from "react-redux";
import thunkMiddleware from "redux-thunk";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import rootReducer from "./Redux/rootReducer";
const composeEnhancers =
(typeof window !== "undefined" &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) ||
compose;
const store = createStore(
rootReducer,
composeEnhancers(applyMiddleware(thunkMiddleware))
);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
serviceWorker.unregister();
In redux reducer you should always return the entire new version of the state, not just the updated parameter
exemple
return Object.assign({},prevState,{field: action.value});
(We don't see your reducer in your post but I guess that this is the problem)
Good documentation here - https://redux.js.org/basics/reducers/
Using redux to manage the state of a component is very bad practice. What you should do instead is to use useState to save the state of each of your inputs and control them with the onChange
Redux should be used ONLY for variables which are UI related and which have to be transported between multiple components all around the website.
https://reactjs.org/docs/hooks-state.html for more information
You need to know that everytime you update your redux store, the store is first copied (fully) then the new values are added and then the current store is replaced by the new one. Which drives to a lot of performance issues and memory leak.
The error is in your store creation
project: createProjectReducer(state.createProject, action)
should be
project: createProjectReducer(state.project, action)
The state is lost by not being passed to the sub reducer