it's my first time here. I'm just starting to learn React and I'm having a little problem creating a weather app. When I try to recall the temp value I get the message: cannot read property "temp" of undefined. I would be very grateful for a hint if someone sees an error. I'm attaching the code
import React, { useState } from "react";
import axios from "axios";
export default function Weather() {
let [city, setCity] = useState("");
let [weather, setWeather] = useState("");
function showWeather(response) {
setWeather(response.data);
}
function handleChange(event) {
setCity(event.target.value);
}
function displayTemperature(event) {
event.preventDefault();
let url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=97a9745b0c3a1f932357060a2331ab49&units=metric`;
axios.get(url).then(showWeather);
}
let form = (
<div>
<form onSubmit={displayTemperature}>
<input type="text" onChange={handleChange} />
<input type="submit" value="Search" />
</form>
</div>
);
return (
<div>
{form}
<ul>
<li>Temperature: {weather.main.temp}°C</li>
<li>Description: {weather.weather[0].description}</li>
<li>Humidity: {weather.main.humidity}%</li>
<li>Wind: {weather.wind.speed}km/h</li>
<li>
<img
src={`http://openweathermap.org/img/wn/${weather.weather[0].icon}#2x.png`}
alt=""></img>
</li>
</ul>
</div>
);
}
In the initial state weather is an empty string so before the API hit all the value that you're accessing from weather will be not available so you could use either optional chaining
weather?.main?.humidity
or && operator
weather && Array.isArray(weather) && weather[0].description
Codesandbox
import React, { useState } from "react";
import axios from "axios";
export default function Weather() {
let [city, setCity] = useState("");
let [weather, setWeather] = useState("");
function showWeather(response) {
setWeather(response.data);
}
function handleChange(event) {
setCity(event.target.value);
}
function displayTemperature(event) {
event.preventDefault();
let url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=97a9745b0c3a1f932357060a2331ab49&units=metric`;
console.log(url);
axios.get(url).then(showWeather);
}
function getImageIcon(weather) {
const value = weather && Array.isArray(weather) && weather[0].icon;
return value;
}
let form = (
<div>
<form onSubmit={displayTemperature}>
<input type="text" onChange={handleChange} />
<input type="submit" value="Search" />
</form>
</div>
);
return (
<div>
{form}
<ul>
<li>Temperature: {weather?.main?.temp}°C</li>
{weather && Array.isArray(weather) && weather[0]?.description}
<li>
Description:{" "}
{weather && Array.isArray(weather) && weather[0].description}
</li>
<li>Humidity: {weather?.main?.humidity}%</li>
<li>Wind: {weather?.wind?.speed}km/h</li>
<li>
<img
src={`http://openweathermap.org/img/wn/${getImageIcon()}#2x.png`}
alt=""
></img>
</li>
</ul>
</div>
);
}
It is showing the error because in the beginning the value of weather is empty string and you are trying to access the property main.temp from it.
You can solve this by using conditional rendering by showing the list only when weather is not empty.
Also not related to this issue but you should add a catch method in displayTemperature method while fetching the data for error handling.
Here is an example below :
import React, { useState } from "react";
import axios from "axios";
export default function Weather() {
let [city, setCity] = useState("");
let [weather, setWeather] = useState("");
function showWeather(response) {
setWeather(response.data);
}
function handleChange(event) {
setCity(event.target.value);
}
function displayTemperature(event) {
event.preventDefault();
let url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=97a9745b0c3a1f932357060a2331ab49&units=metric`;
axios.get(url)
.then(showWeather)
.catch(err => console.log(err));
}
let form = (
<div>
<form onSubmit={displayTemperature}>
<input type="text" onChange={handleChange} />
<input type="submit" value="Search" />
</form>
</div>
);
return (
<div>
{form}
{/* Conditionally rendering the list */}
{weather && (
<ul>
<li>Temperature: {weather.main.temp}°C</li>
<li>Description: {weather.weather[0].description}</li>
<li>Humidity: {weather.main.humidity}%</li>
<li>Wind: {weather.wind.speed}km/h</li>
<li>
<img
src={`http://openweathermap.org/img/wn/${weather.weather[0].icon}#2x.png`}
alt=""></img>
</li>
</ul>
)}
</div>
);
}
Related
First.js
import { useState } from "react";
import { Link } from "react-router-dom";
const First = () => {
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
}
return (
<div className="First">
<h1>This is First Input Page</h1>
<form onSubmit={handleSubmit}>
<dd>data 1</dd>
<input
type="text"
value={name}
onChange={(e) =>
setName(e.target.value)
}
required
></input>
<dd>data 2</dd>
<input
type="text"
value={phone}
onChange={(e) =>
setPhone(e.target.value)
}
required
></input><br/>
<Link to={'/second'} state={{ state: { name : name , phone : phone } }}><button>submit</button></Link>
</form>
</div>
);
}
export default First;
I try to send Object data using Link/state to another component.
Second.js
import {useLocation} from 'react-router-dom';
const Second = () => {
const location = useLocation();
console.log(location.state);
console.log(location.state.name);
return (
<div className="Second">
<h1>This is Second Input Page</h1>
<form>
<dd>data 3</dd>
<input></input>
<dd>data 4</dd>
<input></input><br/>
<button>submit</button>
</form>
</div>
);
}
export default Second;
However, while I can access to (location.state), I can not access to (location.state.name). Why is that?
Output
state: {name: 'Myname', phone: 'myphone'}
[[Prototype]]: Object
--------------------
undefined
The output shows that the code line "console.log(location.state);" works, but to the "console.log(location.state.name);", it shows undefined.
It's because you passed an object with state as the root property, i.e.
state={{ state: { name: name, phone: phone } }}
so to access it in the receiving route it is location.state.state.name.
You really don't need to nest the data you want to pass under a state property when using the Link component, it's not quite the same as when using the navigate function.
<Link to="/second" state={{ name, phone }}>
<button>submit</button>
</Link>
It may also be considered semantically incorrect HTML to nest a button element within an anchor tag (via Link) element. Use the useNavigate hook and issue an imperative navigation action from the form's submit handler. In this case the navigate function's second argument, the options object, *does* expect the state to be passed under the state` property.
Example:
import { Link, useNavigate } from "react-router-dom";
const First = () => {
const navigate = useNavigate();
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
navigate("/second", { state: { name, phone } });
};
return (
<div className="First">
<h1>This is First Input Page</h1>
<form onSubmit={handleSubmit}>
<dd>data 1</dd>
<input
type="text"
value={name}
onChange={(e) =>
setName(e.target.value)
}
required
/>
<dd>data 2</dd>
<input
type="text"
value={phone}
onChange={(e) =>
setPhone(e.target.value)
}
required
/>
<br/>
<button>submit</button>
</form>
</div>
);
};
export default First;
So I have a parent component which contains a form and a child component(this component also has a form , here its a dynamic form meaning when the add button is hit it creates another form below so that user can add a list of parameters of various types . Basically I am trying to achieve state lifting from child to component . I would be really grateful if someone could help me out , I have been stuck on this since a week and I tried a lot . I would appreciate if someone could refactor my code so that it works . I have also attached a gif which shows the form
GIF : https://drive.google.com/file/d/15YXGhvo0OMCh4ch44q4S88wcqOB7i2ew/view?usp=sharing
Parent Component - ParamsForm.js
import React, { useState, useEffect } from 'react'
import { Form } from 'react-bootstrap'
import styles from '../style.module.css'
import Operations from './Operations'
import OperationsFormTest from './OperationsFormTest'
const ParamsForm = () => {
const[isToggled,setIsToggled] = useState(false)
const[formData,setFormData] = useState(
{url:'',endpoint:'',name:'',description:'',type:'',required:''}
)
const handleSubmit = (e) =>{
e.preventDefault()
console.log('Form Data is :' , formData)
}
const handleChangeInput = (index,e) =>{
const values = [...formData]
values[index][e.target.name] = e.target.value
setFormData(values)
}
const handleAddFields = () =>{
setFormData([...formData,{url:'',endpoint:'',name:'',description:'',type:'',required:''}])
}
const handleRemoveFields = (index) =>{
const values = [...formData]
values.splice(index,1)
setFormData(values)
}
useEffect(()=>{
console.log(isToggled)
},[isToggled])
return (
<div className={styles.paramFormsContainer}>
{setFormData}
<form onSubmit={handleSubmit}>
<input type='text' name='url' placeholder='Url..' value={formData.url} onChange={handleChangeInput}></input>
<input type='text' name='endpoint' placeholder='Endpoint...' value={formData.endpoint} style={{flex : 1 }} onChange={handleChangeInput}></input>
<button type='button' onClick={()=>setIsToggled(!isToggled)} className={styles.pathParamFormsBtn}>Path Params</button>
{isToggled && <OperationsFormTest name={formData.name} description={formData.description} type={formData.type} required={formData.required} handleAddFields={handleAddFields} nameFunc={handleChangeInput} descriptionFunc={handleChangeInput} typeFunc={handleChangeInput} requiredFunc={handleChangeInput} handleRemoveFields={handleRemoveFields}></OperationsFormTest>}
<br></br><br></br>
<button type='submit' onClick={handleSubmit}>Submit</button>
</form>
</div>
)
}
export default ParamsForm
Child Component - OperationsFormTest.js
import React, { useEffect, useState } from 'react'
import styles from '../style.module.css'
import {FaInfo,FaFileInvoiceDollar} from 'react-icons/fa'
import ReactTooltip from "react-tooltip";
const OperationsFormTest = ({name,type,description,required,nameFunc,descriptionFunc,typeFunc,requiredFunc,handleAddFields,handleRemoveFields}) =>{
const ChildToParentName = (e) =>{
nameFunc(e)
}
const ChildToParentType = (e) =>{
typeFunc(e)
}
const ChildToParentDescription = (e) =>{
descriptionFunc(e)
}
const ChildToParentRequired = (e) =>{
requiredFunc(e)
}
return(
<>
<div>
<div className={styles.pathParamsFormParentContainer}>
<div className={styles.pathParamsFormChildContainer}>
<label>Name : </label>
<input name='name' type='text' placeholder='Name..' value={name} onChange={ChildToParentName}></input><br></br><br></br>
<label>Description : </label>
<input name='description' type='text' placeholder='Description..' value={description} onChange={ChildToParentDescription}></input><br></br><br></br>
<select name = 'type' value = {type} onChange={ChildToParentType}>
<option>Any</option>
<option>String</option>
<option>Boolean</option>
</select>
<label>Required : </label>
<input name='required' type='text' placeholder='Yes or No..' value={required} onChange={ChildToParentRequired}></input><br></br><br></br>
<button type='button' onClick={()=>handleAddFields()}>Add</button>
<button type='button' onClick={()=>handleRemoveFields()}>Remove</button><br></br><br></br>
</div>
</div>
</div>
</>
)
}
export default OperationsFormTest
I hope you will get some idea from this simple codes.
function Home() {
// Async await is up to you
const onSubmit = async (data)=> {
console.log(data);
}
return (
<Form onSubmit={onSubmit} />
)
}
function Form() {
const [text,setText] = useState("");
// async await is up to you
const handleSubmit = async (e)=> {
e.preventDefault();
await onSubmit(text);
setText("");
}
return (
<form onSubmit={handleSubmit}>
<input type={"text"} value={text} onChange={e=>setText(e.target.value)} />
<input type={"submit"} />
</form>
)
}
Hey I am learning reactjs as much as i have learned I am trying to make note app
my code given below
my App.js file
import React , {useEffect, useState} from "react"
import { nanoid } from "nanoid"
import Editor from './Note/Editor'
import Sidebar from "./Note/Sidebar"
function App() {
const [notes , setNotes] = useState(JSON.parse(localStorage.getItem("notes"))||[])
const [currentNoteID , setCurrentNoteID] = useState(false)
useEffect(()=>{
localStorage.setItem("notes" , JSON.stringify(notes))
},[notes])
function createNewNotes(){
const newNotes = {
id: nanoid(),
title:"untitled",
body: "sdasda",
lastModified: Date.now()
}
setNotes(prevNote => [newNotes , ...prevNote])
setCurrentNoteID(newNotes.id)
}
function deleteNote(noteID){
setNotes(prevNote => prevNote.filter(note=> note.id !== noteID ))
}
function getNotes(){
return notes.find((note)=> note.id === currentNoteID)
}
return (
<div className="note">
<Sidebar
notes={notes}
createNewNotes={createNewNotes}
currentNoteID={currentNoteID}
setCurrentNoteID={setCurrentNoteID}
deleteNote={deleteNote}
/>
<Editor
notes={getNotes()}
currentNoteID={currentNoteID}/>
</div>
);
}
export default App;
my Sidebar.js file
import React from 'react'
import './style.css'
export default function Sidebar(props){
return(
<>
<div className='sidebar' >
<div className='sidebar-header'>
<h3>Notes</h3>
<button className='add' onClick={props.createNewNotes} >Add</button>
</div>
{ props.notes.map((note)=>{
return(
<div key={note.id}
className={`${note.id===props.currentNoteID ? "active" : ""}`}
onClick={()=>props.setCurrentNoteID(note.id)}
>
<div>
<div className="sidebar-tab">
<div className='sidebar-title'>
<p className='title'>Untitled</p>
<button className='delete' onClick={()=>props.deleteNote(note.id)}>Delete</button>
</div>
<p className='note-preview'>summary of text</p>
</div>
</div>
</div>
)
})}
</div>
</>
)
}
my Editor.js file
import React , {useState} from "react";
import './style.css'
export default function Editor(props){
const [edit , setEdit] = useState(props.notes)
function handleChange(event){
const {name , value} = event.target
setEdit(prevNote=> {
return {
...prevNote,
[name] : value
}
})
}
if(!props.currentNoteID)
return <div className="no-note">no note active</div>
return(
<>
<div className="main">
<input type="text" className="main-input" name="title" placeholder="Enter title here" value={edit.title} onChange={handleChange} autoFocus/>
<textarea className="main-textarea" name="body" placeholder="Type your notes" value={edit.body} onChange={handleChange} />
<div className="preview">
<h1 className="preview-title">{edit.title}</h1>
<div className="main-preview">{edit.body}</div>
</div>
</div>
</>
)
}
whenever i click add button or any sidebar button it shows me error
Uncaught TypeError: Cannot read properties of undefined (reading 'title')
please help me out how to fix this issue
You're expecting getNotes (which should probably be named getActiveNote, IMHO) to re-run every time notes or currentNoteID change.
To achieve this, you have to declare it as a callback (useCallback) and to declare its dependencies. Also you want to place the result in state (e.g: activeNote):
const getActiveNote = useCallback(
() => notes.find((note) => note.id === currentNoteID),
[notes, currentNoteID]
);
const [activeNote, setActiveNote] = useState(getActiveNote());
useEffect(() => {
setActiveNote(getActiveNote());
}, [getActiveNote]);
// ...
<Editor note={activeNote} />
... at which point, you no longer need the currentNoteID in the <Editor /> as you can get it from props.note.id.
See it working here: https://codesandbox.io/s/crazy-glade-qb94qe?file=/src/App.js:1389-1448
Note: the same thing needs to happen in <Editor>, when note changes:
useEffect(() => setEdit(note), [note]);
so I currently have a header component in my react js website and I want to set the title of it to an element of an array, but I cant seem to figure out how. here is my code
import Header from './components/Header';
var shoppinglist = []
var currentitem = ""
const App = () => {
function getData(val){
console.warn(val.target.value)
currentitem = val.target.value;
}
function logData() {
shoppinglist.push(currentitem)
console.log(shoppinglist)
}
function deleteItem() {
shoppinglist.pop()
console.log(shoppinglist)
console.log(shoppinglist[0])
}
return (
<div className="Container">
<Header title = "grocery list" />
<input type="text" onChange={getData}></input>
<button onClick={logData}>add item to list</button>
<button onClick={deleteItem}>delete item</button>
<div className="listItems">
<Header title = {shoppinglist[0]} />
</div>
</div>
);
}
export default App;
how would i set the header title to shoppinglist[0]?
You have to have React state in order to render your content - in your case title.
You can read more in react.js
One way of achieving what you asked in question: https://codesandbox.io/s/competent-wildflower-uvusd?file=/App.js
import "./styles.css";
import React from "react";
export default function App() {
const [title, setTitle] = React.useState(null);
const [input, setInput] = React.useState(null);
function getData(val) {
console.warn(val.target.value);
setInput(val.target.value);
}
function deleteItem() {
setTitle(null);
}
return (
<div className="Container">
<input type="text" onChange={getData}></input>
<button onClick={() => setTitle(input)}>add item to list</button>
<button onClick={deleteItem}>delete item</button>
{title && (
<div>
<p>{title}</p>
</div>
)}
</div>
);
}
If you want a dynamic component in react you have to use state-variables. Else React doesn't re-render your code. This could look like this with React Hooks:
import Header from './components/Header';
var currentitem = ""
const App = () => {
const [shoppinglist, setShoppinglist] = useState([]);
function getData(val){
console.warn(val.target.value)
currentitem = val.target.value;
}
function addItem() {
shoppinglist.push(currentitem)
setShoppinglist([...shoppinglist])
}
function deleteItem() {
shoppinglist.pop()
setShoppinglist([...shoppinglist])
}
return (
<div className="Container">
<Header title = "grocery list" />
<input type="text" onChange={getData}></input>
<button onClick={addItem}>add item to list</button>
<button onClick={deleteItem}>delete item</button>
<div className="listItems">
<Header title = {shoppinglist[0]} />
</div>
</div>
);
}
export default App;
So, I made a react app that displays a list of items from a json file as in the pic.
I want to implement a search feature where i can enter the name and it checks for the name in list and scrolls to it.
A person told me about scroll-into-view , but I'm not understand how to make it compare the search term to the names in list.
My App.js code
import React,{useState} from 'react';
import Notes from './Notes';
import './App.css';
function App() {
const [notes] = useState([]);
const handleSubmit= ()=>{
//Upon submitting I want the search functionality to be implemented here . If thats the way to do it.
}
return (
<div className="App">
<div className="App-header">
<form><input type="text" placeholder="Start Typing.." onSubmit={handleSubmit} ></input></form>
<div className="pageTitle">Song Notes :</div>
<Notes thisNotes={notes}/>
</div>
</div>
);
}
export default App;
My Notes.js code:
import React from 'react';
const Notes = ({notes})=>{
const jsonNotes = require('./Notes.json');
const songNotes = jsonNotes.map(note => {
return(
<div key={note.id}>
<li class="noteAsList">
<div className="songTitle">{note.Name}</div>
<pre><br></br>{note.Notes}</pre>
</li>
</div>
)
})
return(
<div className="noteStyle">
{songNotes}
</div>
)
}
export default Notes;
I'm looking to implement such a feature. Either scrolling into view in the page or just displaying the item I asked for.
Thanks for the help in advance.
Codesandbox
My App.js code
import React, { useState } from "react";
import Notes from "./Notes";
import "./App.css";
const jsonNotes = require("./Notes.json");
const App = () => {
const [notes] = useState([]);
const handleSubmit = event => {
if (event.key === "Enter") {
console.log(event.target.value);
const obj = jsonNotes.find(item => item.Name === event.target.value);
const el = document.getElementById(obj.id);
if (el)
el.scrollIntoView({
behavior: "smooth",
block: "start",
inline: "center"
});
}
};
return (
<div className="App">
<div className="App-header">
<input
type="text"
placeholder="Start Typing.."
onKeyPress={handleSubmit}
/>
<div className="pageTitle">Song Notes :</div>
<Notes thisNotes={notes} />
</div>
</div>
);
};
export default App;
My Notes.js code:
import React from "react";
const jsonNotes = require("./Notes.json");
const Notes = ({ notes }) => {
const songNotes = jsonNotes.map(note => {
return (
<div id={note.id} key={note.id}>
<li className="noteAsList">
<div className="songTitle">{note.Name}</div>
<pre>
<br />
{note.Notes}
</pre>
</li>
</div>
);
});
return <div className="noteStyle">{songNotes}</div>;
};
export default Notes;