So in my program, I am statically creating and removing players. However, the editing of a players's attribute isn't working.
I have 3 action types. ADD_PLAYER, REMOVE_PLAYER, EDIT_PLAYER
For each one of them, I create an action generator, which contains a type and any other parameters accordingly. Here is my full code
import { createStore, combineReducers } from 'redux';
import uuid from 'uuid';
// ADD_PLAYER
const addPlayer = (
{
firstName = '',
lastName = '',
age = 0,
position = ''
} = {}) => ({
type: 'ADD_PLAYER',
player: {
id: uuid(),
firstName,
lastName,
age,
position
}
});
// REMOVE_PLAYER
const removePlayer = ( {id} = {} ) => ({
type: 'REMOVE_PLAYER',
id
});
// EDIT_PLAYER
const editPlayer = (id, updates) => ({
type: 'EDIT_PLAYER',
id,
updates
})
const playersReduxDefaultState = [];
// The Player reducer
const playersReducer = (state = playersReduxDefaultState, action) => {
switch(action.type) {
case 'ADD_PLAYER':
return [
...state,
action.player
]
case 'REMOVE_PLAYER':
return state.filter(({id}) => id !== action.id)
case 'EDIT_PLAYER':
return state.map((player) => {
if(player.id === action.id) {
return {
...player,
...action.updates
}
} else {
return player
}
});
default:
return state;
}
};
const store = createStore(
combineReducers({
players: playersReducer
})
)
store.subscribe(() => {
console.log(store.getState())
});
store.dispatch(
addPlayer(
{
firstName: 'Theo',
lastName: 'Tziomakas',
age: 38,
position: 'Striker'
}
))
const playerOne = store.dispatch(
addPlayer(
{
firstName: 'Vasilis',
lastName: 'Tziastoudis',
age: 38,
position: 'Defender'
}
))
store.dispatch(removePlayer({ id: playerOne.player.id}));
// Edit player's one age.
store.dispatch(editPlayer(playerOne.player.id, { age: 29 }));
What am I missing?
Thanks,
Theo.
Related
How do I store the input data as objects in an array using useState? Please help.
I need help. I am not able to get the desired output to display the input values.
const Form = () => {
const [allNotes, setAllNotes] = useState([{}]);
const [notes, setNotes] = useState({
name: "",
age: "",
class: "",
request: "",
});
const nameChangeHandler = (event) => {
setNotes((prevState) => {
const newState = { ...prevState, name: event.target.value };
return newState;
});
};
const ageChangeHandler = (event) => {
setNotes((prevState) => {
const newState = { ...prevState, age: event.target.value };
return newState;
});
};
const classChangeHandler = (event) => {
setNotes((prevState) => {
const newState = { ...prevState, class: event.target.value };
return newState;
});
};
const requestChangeHandler = (event) => {
setNotes((prevState) => {
const newState = { ...prevState, request: event.target.value };
return newState;
});
};
const submitHandler = () => {
setAllNotes((prevState) => {
const newState = {
...prevState,
name: notes.name,
age: notes.age,
class: notes.class,
request: notes.request,
};
return newState;
});
};
Everything looks good, maybe except for two small mistakes:
Let's make the initial state for all notes just an empty array, like
const [allNotes, setAllNotes] = useState([]);
The new array inside the setAllNotes should be array not object, like:
const submitHandler = () => {
setAllNotes((prevState) => {
const newState = [
...prevState,
{
name: notes.name,
age: notes.age,
class: notes.class,
request: notes.request,
}
];
return newState;
});
};
Hope this makes it work!
I want to link this small react project to a database, it's my first time so I don't really know anything about linking frontend to backend except that we need to use an APi.
import React, { useState } from "react";
import { v4 as uuidv4 } from "uuid";
const ControlledInputs = () => {
const [person, setPerson] = useState({
firstName: "",
email: "",
age: "",
phoneNumber: "",
});
const [people, setPeople] = useState([]);
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setPerson({ ...person, [name]: value });
};
const handleSubmit = (e) => {
e.preventDefault();
if (person.firstName && person.email && person.age && person.phoneNumber) {
console.log(person);
const newPerson = { ...person, id: uuidv4() };
setPeople((person) => {
return [...person, newPerson];
});
console.log(people);
} else {
console.log("error");
}
};
this where the form starts it's a simple form of 4 inputs
return (
<>
Name :
Email :
Age :
Phone Number :
add person
{people.map((person) => {
const { id, firstName, email } = person;
return (
{firstName}
{email}
);
})}
</>
);
};
export default ControlledInputs;
If it is RESTful API method, use axios to patch the data.
https://github.com/axios/axios
axios
.post("/user", {
firstName: person.firstName,
...
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
I'm building a e-commerce store where I have the following data structure:
productsData.js
export const storeProducts = [
{
id: 1,
title: "Santos",
img: "img/pfs - black.png",
price: 59.70,
description: "Lorem Ipsum",
gender: ["Feminine", "Masculine"],
info:
"Lorem Ipsum",
inCart: false,
count: 0,
total: 0
}
];
export const detailProducts = {
id: 1,
title: "Pecadores Feitos Santos",
img: "img/pfs - black.png",
price: 59.70,
description: "Lorem ipsum",
gender: ["Feminine", "Masculine"],
info:
"Lorem ipsum.",
inCart: false,
count: 0,
total: 0
};
I have a Context React file that is my provider and consumer:
context.js
import React, { Component } from 'react'
import { storeProducts, detailProducts } from './productsData';
const ProductContext = React.createContext();
// Provider and Consumer
class ProductProvider extends Component {
state = {
products: [],
detailProducts: detailProducts,
cart: [],
modalOpen: false,
modalProduct: detailProducts,
cartTotal: 0
};
componentDidMount() {
this.setProducts();
}
setProducts = () => {
let tempProducts = [];
storeProducts.forEach(item => {
const singleItem = {...item};
tempProducts = [...tempProducts, singleItem];
});
this.setState(() => {
return { products: tempProducts };
// console.log("State products: ", storeProducts[0].color[0])
});
};
getItem = id => {
const product = this.state.products.find(item => item.id === id);
return product;
};
handleDetail = id => {
const product = this.getItem(id);
this.setState(() => {
return { detailProducts: product };
});
};
addToCart = id => {
let tempProducts = [...this.state.products];
const index = tempProducts.indexOf(this.getItem(id));
const product = tempProducts[index];
// console.log(product.gender);
product.inCart = true;
product.count = 1;
const price = product.price;
product.total = price;
this.setState(() => {
return { products: tempProducts, cart: [...this.state.cart,product] }
}, () => { this.addTotal();});
}
openModal = id => {
const product = this.getItem(id);
this.setState(() => {
return {modalProduct: product, modalOpen: true}
})
}
closeModal = () => {
this.setState(() => {
return {modalOpen: false}
})
}
increment = (id) => {
let tempCart = [...this.state.cart];
const selectedProduct = tempCart.find(item => item.id === id);
const index = tempCart.indexOf(selectedProduct);
const product = tempCart[index];
product.count = product.count + 1;
product.total = product.count * product.price;
this.setState(() => {
return {
cart: [...tempCart]
}
}, () => { this.addTotal() })
}
decrement = (id) => {
let tempCart = [...this.state.cart];
const selectedProduct = tempCart.find(item => item.id === id);
const index = tempCart.indexOf(selectedProduct);
const product = tempCart[index];
product.count = product.count - 1;
if(product.count === 0) {
this.removeItem(id);
}
else {
product.total = product.count * product.price;
this.setState(() => {
return {
cart: [...tempCart]
}
}, () => { this.addTotal() })
}
}
removeItem = (id) => {
let tempProducts = [...this.state.products];
let tempCart = [...this.state.cart];
tempCart = tempCart.filter(item => item.id !== id);
const index = tempProducts.indexOf(this.getItem(id));
let removedProduct = tempProducts[index];
removedProduct.inCart = false;
removedProduct.count = 0;
removedProduct.total = 0;
this.setState(() => {
return {
cart:[...tempCart],
products: [...tempProducts]
}
}, ()=> {
this.addTotal();
})
}
clearCart = () => {
this.setState(() => {
return { cart: [] };
}, () => {
this.setProducts();
this.addTotal();
})
}
addTotal = () => {
let total = 0;
this.state.cart.map(item => (total += item.total));
this.setState(() => {
return {
cartTotal: total
}
})
}
render() {
return (
<ProductContext.Provider value={{
...this.state,
handleDetail: this.handleDetail,
addToCart: this.addToCart,
openModal: this.openModal,
closeModal: this.closeModal,
increment: this.increment,
decrement: this.decrement,
removeItem: this.removeItem,
clearCart: this.clearCart
}}
>
{this.props.children}
</ProductContext.Provider>
)
}
}
const ProductConsumer = ProductContext.Consumer;
export { ProductProvider, ProductConsumer };
Everything works just fine, but here's where the problems start:
Details.js
import React, { Component } from 'react';
import { ProductConsumer } from '../context';
import { Link } from 'react-router-dom';
import { ButtonContainerSecondary } from './ButtonSecondary';
import { ButtonDetails } from './ButtonDetails';
import { ColorButton } from './ColorButton';
import PropTypes from 'prop-types';
export default class Details extends Component {
render() {
return (
<ProductConsumer>
{value => {
const {id, img, price, description, color, gender, info, title, inCart} = value.detailProducts;
return (
<div className="container pb-5">
<div className="row">
<div className="col-10 mx-auto text-center text-slanted my-5">
{gender.map((item, key) => (
<span>{" "}<ButtonDetails key={key} onClick={() => { this.setState({gender: key}); console.log(key)}}
</div>
</div>
</div>
)
}}
</ProductConsumer>
)
}
}
Details.propTypes = {
product: PropTypes.shape({
color: PropTypes.arrayOf(PropTypes.string),
gender: PropTypes.arrayOf(PropTypes.string)
})
}
I can't seem to figure out how to pass in the state in the nested array gender to the next level. I do get the console.log(key) right, but it gets lost as I move up to the cart. I would like to give the user the chance to choose from a feminine or masculine shirt:
CartItem.js
import React from 'react'
export default function CartItem({ item, value }) {
const {id, title, img, price, gender, total, count} = item;
const {increment, decrement, removeItem} = value;
return (
<div className="col-10 mx-auto col-lg-2">
<span className="d-lg-none">Product: </span> {title} {gender} {console.log(gender)}
</div>
);
}
Here the console.log(gender) returns both items of the array altogether ("FeminineMasculine").
I'm a newbie and would really appreciate your help. Sorry if anything!
Expected behavior: all messages in a chat render seamlessly at the same time
Observed behavior: upon mounting component or sending a new message, the messages disappear and then re-render one-by-one in chronological order. Here is a gif of the current behavior: https://imgur.com/a/GYYBzAb
I'm fairly certain this is to do with how I'm handling the interaction between firestore and component state but I'm unsure about how to proceed.
export default class Chat extends React.Component {
state = {
messages: [],
currentUser: null,
chatID: '',
courseTitle: ''
};
componentDidMount(){
// get user info from firestore
let user = firebase.auth().currentUser._user
firestore().collection("users").doc(user.uid).get().then(doc => {
data = doc.data()
this.setState({currentUser: {
name: data.name,
email: data.email,
avatar: data.avatar,
_id: doc.id,
}})
})
// make a call to firestore to retrieve the chat data
let chatID = this.props.navigation.state.params.id
this.setState({chatID: chatID})
firestore().collection("chats").doc(chatID).onSnapshot((doc) => {
this.setState({ messages: [], courseTitle: doc.data().courseTitle })
let newArray = []
doc.data().messages.map(item => {
firestore().collection("messages").doc(item).onSnapshot((doc) => {
let message = doc.data()
message['_id'] = doc.id
newArray.push(message)
this.setState(previousState => ({
messages: GiftedChat.append(previousState.messages, message)
}))
})
})
})
}
get user() {
currentUser = this.state.currentUser
return {
name: currentUser.name,
email: currentUser.email,
avatar: currentUser.avatar.uri,
_id: currentUser._id
};
}
get timestamp() {
return firebase.database.ServerValue.TIMESTAMP;
}
onSend(messages = []) {
for (let i = 0; i < messages.length; i++) {
const { text, user } = messages[i];
const message = {
text,
user,
timestamp: this.timestamp,
};
firestore().collection("messages").add(message).then((doc) => {
const id = doc.id
firestore().collection("chats").doc(this.state.chatID).update({
messages: firestore.FieldValue.arrayUnion(id)
})
})
}
}
goBack = () => {
this.props.navigation.goBack()
}
render() {
return (
<>
{this.state.currentUser ?
<>
<BackHeader title={this.state.courseTitle} command={this.goBack} titleSize={12} />
<GiftedChat
showUserAvatar={true}
renderUsernameOnMessage={true}
messages={this.state.messages}
onSend={messages => this.onSend(messages)}
user={this.user}
/>
</>
: null }
</>
);
}
}
In my project I'm using tcomb-form-native library to validation a form. Redux working fine but I can't pass value of inputs to reducer. I have to do this, because I want to create array with data from fields.
How can I pass values of my inputs to reducer?
Or maybe it's not possible with this library and I have to use another one?
Form.js
const mapDispatchToProps = dispatch => {
return {
closeExpenseDialog: (value) => dispatch({type: 'CLOSE_EXPENSE_DIALOG'}),
};
};
const mapStateToProps = state => {
return {
value: state.closeExpenseDialog.value,
};
};
const Form = t.form.Form;
const Expense = t.struct({
expense: t.String,
cost: t.Number
});
const options = {
fields: {
expense: {
error: 'This field is required'
},
cost: {
error: 'This field is required'
}
}
};
handleClick = () => {
const value = this._form.getValue();
if (value) {
console.log(value);
this.props.closeExpenseDialog(value);
} else {
console.log('validation failed');
}
}
<Form
type={Expense}
ref={c => this.props._form = c}
options={options}
value={this.props.value}
/>
<ActionButton
onPress={this.props.closeExpenseDialog}
title={title}
/>
Reducer.js
const initialState = {
value: {}
};
const mainReducer = (state = initialState, action) => {
switch (action.type) {
case 'CLOSE_EXPENSE_DIALOG':
console.log('it works')
console.log(state.value) //undefined
default:
return state;
}
};
I needed add onChange() attribute and use it to pass object value to the Reducer.
Form.js
const Expense = t.struct({
expense: t.String,
cost: t.Number
});
const options = {
fields: {
expense: {
error: 'This field is required'
},
cost: {
error: 'This field is required'
}
}
};
handleClick = () => {
const value = this._form.getValue();
if (value) {
this.props.submitExpenseDialog();
}
}
<Form
type={Expense}
ref={c => this._form = c}
options={options}
value={this.props.value}
onChange={this.props.changeExpenseInputs}
/>
<ActionButton
onPress={this.handleClick}
title={title}
/>
Reducer.js
const initialState = {
value: {}
};
const mainReducer = (state = initialState, action) => {
switch (action.type) {
case 'SUBMIT_EXPENSE_DIALOG':
console.log(state.value)
default:
return state;
}
};