Can't display data in localhost browser - node.js

I creating an app that stores data but when i finish the prompt input i get this error:
Here is my CptList.js
import React, { Component } from 'react';
import { Container, Button } from 'reactstrap';
import uuid from 'uuid';
export default class CpdList extends Component{
state = {}
handleClick = () => {
const date = prompt('Enter Date')
const activity = prompt('Enter Activity')
const hours = prompt('Enter Hours')
const learningStatement = prompt('Enter Learning Statement')
const evidence = prompt('YES! or NO!')
this.setState(state => ({
items: [
...state.items,
{
id: uuid(),
date,
activity,
hours,
learningStatement,
evidence
}
]
}));
}
render() {
const { items } = this.state;
return (
<Container>
<Button
color='dark'
style={{marginBottom: '2rem'}}
onClick={this.handleClick}
>Add Data</Button>
<Button
color='dark'
style={{marginBottom: '2rem'}}
onClick={() => { this.handleClick(items._id) }}
>Delete Data</Button>
</Container>
);
};
};
Can someone please tell me what im doing wrong? I am also having trouble with my delete function, this is my delete coding in my backend:
//Delete a Item
router.delete('/:id', (req, res) => {
Item.findById(req.params.id)
.then(item => item.remove().then(() => res.json({ success: true })))
.catch(err => res.status(404).json({ success: false }));
});

I think you have to initialize state with:
state = { items:[] }
The first time you add item to undefined empty list.
Moreover I think missing a state.items.map somewhere (at least for delete button)

state = [] // convert to array beacuse use map() or other javascipt method
this.setState(state => ({
items: [
// do not speard maybe
{
id: uuid(),
date,
activity,
hours,
learningStatement,
evidence
}
]
}));
plz write handleClick function
tell me working or not

Related

How to update state in Context using Hooks in MERN Stack Application

I'm trying to find a way to update my "user" state, but I'm stuck here for 3 days already, I need some help.
Here is my user context:
import React, {useEffect, useState} from 'react';
export const UserContext = React.createContext({})
const UserProvider = UserContext.Provider;
const UserContextProvider = (props) => {
const [user, setUser] = useState({})
useEffect(() => {
fetch(`${API}/auth/user`, {
method: 'GET',
withCredentials: true,
credentials: 'include'
})
.then (response => response.json())
.then (response => {
setUser(response.user)
})
.catch (error => {
console.error (error);
});
}, [setUser])
console.log(user)
return (
<UserProvider value={{user, setUser}}>
{props.children}
</UserProvider>
)
}
export default UserContextProvider;
Here is where I'm trying to update the user. In my case I'm trying to push an object in user.cart array, cuz everything on the back-end is fine, but in the front-end the state is not updating:
First I'm using the UserContext:
const Products = () => {
const {user, setUser} = useContext(UserContext) ...
And then here I'm trying to update the user state, BUT when I click the button it logged me out:
<button className="addTo--Cart--Button--Container">
<FaShoppingCart onClick={() => {addToCart(user._id, product); setUser(oldState => oldState.cart.push(product))}}/>
</button>
After this logged me out, the console.log(user) which is in UserContextProvider function log only the user.cart updated lenght.
AND one more:
How to remove item from context:
Here is my remove function:
const removeFromContextCart = (id) => {
console.log(id)
const updatedCart = user.cart.filter((item) => item.id !== id);
setUser(oldState => ({
...oldState,
cart: [
...oldState.cart,
updatedCart
]
}))
}
And my button:
<button className="remove--Button" onClick={() => {removeFromCart(user._id, product); setUser(removeFromContextCart(product._id))}}> REMOVE</button>
Try updating the user state in this way
setUser(oldState => ({
...oldState,
cart: [
...oldState.cart,
product
]
}))

React | Why the defaultValue of the input isn't being updated?

I have a stateful component that calls a CEP promise, to fetch data from post offices. This data is fetched when the Zip input is fulfilled with 9 chars - 8 number and an '-' - and return an object with desired information.
Heres the function:
const handleZipCode = useCallback(
async ({ target }: ChangeEvent<HTMLInputElement>) => {
const { value } = target;
try {
if (value.length === 9 && isDigit(value[8])) {
const zip = await cep(value);
if (zip?.city) {
setZipData(zip);
} else
addressFormRef.current?.setErrors({
user_zip_code: 'CEP not found',
});
}
} catch (e) {
addressFormRef.current?.setErrors({
user_zip_code: e.message ?? 'CEP not found',
});
}
},
[isDigit]
);
Then, on the return I have some fields, example:
<fieldset>
<legend>Address</legend>
<Input
mask=''
name='user_address'
placeholder='Rua um dois três'
defaultValue={zipData.street}
/>
</fieldset>
Here's the Input component:
const Input: React.FC<InputProps> = ({ name, ...rest }) => {
const { fieldName, defaultValue, registerField, error } = useField(name);
const inputRef = useRef(null);
useEffect(() => {
registerField({
name: fieldName,
ref: inputRef.current,
path: 'value',
// eslint-disable-next-line
setValue(ref: any, value: string) {
ref.setInputValue(value);
},
// eslint-disable-next-line
clearValue(ref: any) {
ref.setInputValue('');
},
});
}, [fieldName, registerField]);
return (
<Container>
<ReactInputMask ref={inputRef} defaultValue={defaultValue} {...rest} />
{error && <Error>{error}</Error>}
</Container>
);
};
However the zipData seems to update, but the default value is not fulfilled. What I'm doing wrong?
The default value will not change, as unform is an uncontrolled form library, the defaultValue will be set on the first render of the page and then will not change anymore.
To fix your problem you can do something like:
// on your handleZipCode function
formRef.current.setData({
zipData: {
street: zipResult.street,
},
});

submit button disabled when logging in a user

Hi I am making the logging in functionality and for some reason when I
fill in all the input fields my button stays disabled and I cant submit it.
this is the renderButton function...
renderButton(label) {
return (
<button
disabled={this.validate() ? true : false}
className="btn btn-primary"
>
{label}
</button>
);
}
this is the login form...
import React, { Component } from "react";
import Joi from "joi-browser";
import Form from "./form";
import { login } from "../services/authService";
class LoginForm extends Form {
state = {
data: { username: "", password: "" },
errors: {}
};
schema = {
email: Joi.string()
.required()
.label("Email"),
password: Joi.string()
.required()
.label("Password")
};
doSubmit = async () => {
//call server
const { data } = this.state;
await login(data.email, data.password);
};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
{this.renderInput("email", "Email")}
{this.renderInput("password", "Password", "password")}
{this.renderButton("Login")}
</form>
</div>
);
}
}
export default LoginForm;
this is the validation functions where both validate and vaidate property is in it...
validate = () => {
const options = { abortEarly: false };
const { error } = Joi.validate(this.state.data, this.schema, options);
if (!error) return null;
const errors = {};
for (let item of error.details) errors[item.path[0]] = item.message;
return errors;
};
validateProperty = ({ name, value }) => {
const obj = { [name]: value };
const schema = { [name]: this.schema[name] };
const { error } = Joi.validate(obj, schema);
return error ? error.details[0].message : null;
};
Looks like the render function is not called each time your input changes, maybe it is because you are extending some Form and not React. It is anti pattern to make a deep nesting, just extend React, if you want to add some functionality you can wrap your component with HOC (higher order component function).

Cannot read property from props in react component

In ChatRoom Component, I am trying to load chat between 2 users to render the names of users of the chat. To get the chat, I am firing off getCurrentChat function.
ChatRoom Component
// importing everything
import { getCurrentChat } from '../../actions/chatActions';
class ChatRoom extends Component {
componentDidMount() {
// loading chat between 2 people
this.props.getCurrentChat(this.props.match.params.chatId);
};
render() {
const { loadingCurrentChat } = this.props.chat;
console.log(this.props.chat.currentChat);
return (
<div className="container">
{loadingCurrentChat ? <Spinner /> : (
<div className="row">
<h3>ChatId: {this.props.chat.currentChat._id}</h3>
<h2>Chat between {this.props.chat.currentChat.user1.name} и {this.props.chat.currentChat.user2.name}</h2>
</div>
)}
</div>
)
}
}
const mapStateToProps = (state) => ({
auth: state.auth,
chat: state.chat
});
export default connect(mapStateToProps, { getCurrentChat })(withRouter(ChatRoom));
chatActions.js
export const getCurrentChat = (chatId) => (dispatch) => {
dispatch(setLoadingCurrentChat());
axios.get(`/chat/${chatId}`)
.then(res =>
dispatch({
type: GET_CURRENT_CHAT,
payload: res.data
})
)
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err
})
);
};
chatReducer.js
// importing everything
const initialState = {
currentChat: {},
loadingCurrentChat: false,
};
export default function (state = initialState, action) {
switch (action.type) {
case SET_LOADING_CURRENT_CHAT:
return {
...state,
loadingCurrentChat: true
}
case GET_CURRENT_CHAT:
return {
...state,
currentChat: action.payload,
loadingCurrentChat: false
}
}
}
server file where I handle requests from chatActions.js -
chatController.js
// requiring everything
exports.getCurrentChat = (req, res) => {
const chatId = req.params.chatId;
Chat.findById(chatId)
.populate('user1')
.populate('user2')
.exec()
.then(chat => res.json(chat))
.catch(err => res.status(400).json(err));
};
When I try console.log the currentChat in ChatRoom, it correctly shows the chat.
currentChat:
messages: []
user1: {
_id: "5d1328a91e0e5320706cdabb",
name: "sarvar",
}
user2: {
_id: "5d131405ce36ce0ebcf76ae1",
name: "jalol makhmudov"
}
__v: 0
_id: "5d329aea3f34fe0b8c6cf336"
If I render currentChat._id (see <h3> element in ChatRoom) it correctly displays it.
But if I render currentChat.user1.name and currentChat.user2.name (see <h2> element in ChatRoom) it gives an error
TypeError: Cannot read property 'name' of undefined
Solution
Initialize state with a more accurate shape.
const initialState = {
currentChat: {
user1: {}
},
loadingCurrentChat: false,
};
If you cannot do that, put a check like currentChat.user1 && currentChat.user1.name before accessing it in JSX.
Explanation
getCurrentChat is a request which means it will take time to fetch the data. React does not wait for the request to be completed for rendering. One of the reasons why we define initialState is because while the request is being completed, React uses initialState to render.
In your case, initialState is defined as,
const initialState = {
currentChat: {},
loadingCurrentChat: false,
};
In JavaScript, when you define an empty object currentChat: {}, you can access its immediate child without any error. Therefore currentChat._id is accessible but since currentChat.user1 is undefined, currentChat.user1.name will throw an error.

Not understanding why im getting a TypeError: Cannot read property '_id' of undefined in React

I'm trying to figure out why my code isn't working but I'm still not understanding why I'm getting this type error.
import React, { Component } from 'react';
import axios from 'axios'
class List extends Component {
state = {
title: '',
description: ''
}
componentDidMount(){
const initialState = {
_id: this.props.list._id,
title: this.props.list.title,
description: this.props.list.description
}
this.setState(initialState)
}
handleChange = (event) => {
const { value, name } = event.target
this.setState({[name]: value})
}
handleDelete = () => {
axios.delete(`/api/lists/${this.state._id}`).then(() => {
this.props.getAllLists()
})
}
handleUpdate = () => {
axios.patch(`/api/lists/${this.state._id}`, this.state).then(() => {
console.log("Updated List")
})
}
render() {
return (
<div>
<input onBlur={this.handleUpdate}
onChange={this.handleChange}
type="text" name="title"
value={this.state.title}
/>
<textarea onBlur={this.handleUpdate}
onChange={this.handleChange}
name="description" value={this.state.description}
/>
<button onClick={this.handleDelete}>X</button>
</div>
)
}
}
export default List
This is the Error msg at this link
Added the other part
import React, { Component } from 'react';
import axios from 'axios'
import List from './List';
class ListPage extends Component {
state = {
user: {},
lists: []
}
componentDidMount() {
this.getAllLists()
}
getAllLists = () => {
// make an api call to get one single user
// On the server URL is '/api/users/:userId'
const userId = this.props.match.params.userId
axios.get(`/api/users/${userId}`).then(res => {
this.setState({
user: res.data,
lists: res.data.lists
})
})
}
handleCreateNewList = () => {
const userId = this.props.match.params.userId
const payload = {
title: 'List Title',
description: 'List Description'
}
axios.post(`/api/users/${userId}/lists`, payload).then(res => {
const newList = res.data
const newStateLists = [...this.state.lists, newList]
this.setState({ lists: newStateLists })
})
}
render() {
return (
<div>
<h1>{this.state.user.username}'s List Page</h1>
onClick={this.handleCreateNewList}
New Idea
{this.state.lists.map(list => (
<List getAllLists={this.getAllLists} key={list._id} list={list}/>
))}
</div>
)
}
}
export default ListPage;
Sorry I can't comment yet. The error is because no 'list' prop is being passed to the component. Are you using the component like this:
<List list={{_id: 'someId', title: 'someTitle', description: 'someDesc'}} />
Also, why are you overwriting the state when the component mounts instead of setting the initial state?
I think you should first check if "this.state.lists" is empty or not, before passing the props.

Resources