Changing div text value by clicking on a li item - reactjs

i want to change the text value in a div by clicking on a ul li item.
const text = {
value1 : 'blabla1',
value2 : 'blabla2',
value3 : 'blabla3'
}
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<div> </div>
By clicking on li 1 the div get the value1, by clicking on li 2 the div get the value2 etc.
Can someone give me some advice, thank you

i am write code
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const text = [
{ id: 1, value: "blabla1" },
{ id: 2, value: "blabla2" },
{ id: 3, value: "blabla3" }
];
const [textSelected, setTextSelected] = useState("");
const selectLi = (id) => {
let index = text.findIndex((x) => x.id === id);
if (index === -1) return;
setTextSelected(text[index].value);
};
return (
<>
<ul>
{text.map((x) => (
<li
onClick={() => {
selectLi(x.id);
}}
>
{x.id}
</li>
))}
</ul>
<br />
<div>{textSelected}</div>
</>
);
}
Work Demo

Here is another approach:
import React, { useState } from "react";
export default function App() {
const [listValues, setListValues] = useState([1, 2, 3]);
const text = { value1: "blabla1", value2: "blabla2", value3: "blabla3" };
const showTextValue = (index) => {
const newValues = [...listValues];
newValues[index] = Object.values(text)[index];
setListValues(newValues);
};
const content = listValues.map((val, index) => (
<li key={index} onClick={() => showTextValue(index)}>
{val}
</li>
));
return (
<div className="App">
<ul>{content}</ul>
</div>
);
}

import React from "react";
import "./styles.css";
export default function App() {
const clickHandler = (e) => {
alert("value is " + e.target.id);
let item = document.getElementById(e.target.id);
console.log(item.getAttribute("name"));
};
return (
<div className="App">
<ul>
<li id="blabla1" name="el1" onClick={clickHandler}>
1
</li>
<li id="blabla2" name="el2" onClick={clickHandler}>
2
</li>
<li id="blabla3" name="el3" onClick={clickHandler}>
3
</li>
</ul>
</div>
);
}
CodeSandbox example. You can also assign a value to a variable by using useState.

Related

useEffect is not rendering an array on DOM

I am populating an array with dummy data and once it is done, using useEffect, i'm trying to delete the the element on first index and update it on the DOM. The array is being updated on console but the changes doesn't reflect on DOM.
import './App.css';
import { useState,useEffect } from 'react';
import {faker} from '#faker-js/faker'
function App() {
var catsarray = []
const [cats, changecat] = useState(()=>{
for (let index = 0; index < 10; index++) {
catsarray.push(faker.animal.cetacean())
}
return catsarray
})
useEffect(()=>{
},[cats])
const removecat = () => {
cats.shift()
changecat(cats)
}
return (
<div className="App">
<h1> List of cats </h1>
<div className='wrapper'>
<ul>
<>
{catsarray.length > 2 ?
cats.map((title, index)=>(
<li key={index}> {index} : {title} </li>
)) : 'Array is empty' }
</>
</ul>
</div>
<button title='button' onClick={removecat}> Click me </button>
</div>
);
}
export default App;
The reason is like #Jacob Smit said:
React uses referential comparisons to determine whether or not a value has changed. If you mutate (change) the state and provide it back to the setState function react sees the same value as it already has stored and thinks there is no operation to be carried out
So you need to use a different refernece when mutating a state
for example
// assign a new array
let tempCats = [...cats]
// operate this new array
tempCats.shift()
// set the new array to state
changecat(tempCats)
Or like #Jacob Smit's suggestion
changecat(cats => cats.filter((_, i) => i !== 0))
a example from your question with a little modify
import React from "react"
import { useState, useEffect } from 'react';
function App() {
var faker = ["steve", "john", "cat", "dog", "alex", "big"]
var catsarray = []
const [cats, changecat] = useState(() => {
for (let index = 0; index < faker.length; index++) {
catsarray.push(faker[index])
}
return catsarray
})
useEffect(() => {
}, [cats])
const removecat = () => {
let tempCats = [...cats]
tempCats.shift()
console.log(tempCats)
changecat(tempCats)
// or #Jacob Smit's suggestion
//changecat(cats => cats.filter((_, i) => i !== 0))
}
return (
<div>
<h1> List of cats </h1>
<div>
<ul>
<>
{cats.length > 2 ?
cats.map((title, index) => (
<li key={index}> {index} : {title} </li>
)) : 'Array is empty'}
</>
</ul>
</div>
<button title='button' onClick={removecat}> Click me </button>
</div>
);
}
export default App;
a code snippet display
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
function App() {
var faker = ["steve", "john", "cat", "dog", "alex", "big"]
var catsarray = []
const [cats, changecat] = React.useState(() => {
for (let index = 0; index < faker.length; index++) {
catsarray.push(faker[index])
}
return catsarray
})
React.useEffect(() => {
}, [cats])
const removecat = () => {
let tempCats = [...cats]
tempCats.shift()
console.log(tempCats)
changecat(cats => cats.filter((_, i) => i !== 0))
}
return (
<div>
<h1> List of cats </h1>
<div>
<ul>
{cats.length > 2 ?
cats.map((title, index) => (
<li key={index}> {index} : {title} </li>
)) : 'Array is empty'}
</ul>
</div>
<button title='button' onClick={removecat}> Click me </button>
</div>
);
}
</script>
<script type="text/babel">
ReactDOM.render(
<App></App>
, document.getElementById("root"));
</script>

<button> that changes "navigation titles" with "content field" / passing data from child to parent [duplicate]

In <Nav/> component, "click event" on chevron <button>, triggers nextTitle(length) function in useNextTitle.js custom hook. This function sets the value of val, which is being returned by useNextTitle.js. How to pass that new val to App.js ?
Bigger picture: I want to change the display between <Dod /> and <Analogia /> (in App.js), after "click event" in <Nav /> (figured out val would be helpful for that, as a parameter in Conditional Statement).
Functionality I`m trying to achieve is visualized on the website I done with vanilla Java Script : link (the blue navigation, changes "main pages" with "titles" when chevron clicked)
App.js
import Nav from "./components/Nav";
import Dod from "./components/Dod";
import Analogia from "./components/Analogia";
function App() {
return (
<div className="App">
<Nav />
<Dod />
<Analogia />
</div>
);
}
export default App
Nav.js
import useNextTitle from './useNextTitle';
import './Nav.css';
const Nav = () => {
const navData = [
{id: 0, text: "DOD"},
{id: 1, text: "analogia"}
]
const length = navData.length;
const { val, nextTitle } = useNextTitle();
return (
<nav>
<div>
{/* titles */}
<ul>
<li key="li1">
{navData.map((title, index) => {
return (
<div
className={index === val ? "active" : "display-none"} key={title.id}>
{title.text}
</div>
)
})}
</li>
</ul>
{/* chevron button */}
<div>
<button onClick={() => nextTitle(length)}>
<span className="material-icons">
chevron_right
</span>
</button>
</div>
</div>
</nav>
)
}
export default Nav
useNextTitle.js
import { useState } from 'react';
const useNextTitle = () => {
const [val, setVal] = useState(0);
const nextTitle = (length) => {
setVal(val === length -1 ? 0 : val + 1 )
console.log("hook vav = " + val)
}
return { val, nextTitle }
}
export default useNextTitle;
Move the useNextTitle hook/state up to App and pass val and nextTitle down to Nav to toggle/update the state. Use val to conditionally render Dod and Analogia.
Example:
function App() {
const { val, nextTitle } = useNextTitle();
return (
<div className="App">
<Nav {...{ val, nextTitle }} />
{val === 0 && <Dod />}
{val === 1 && <Analogia />}
</div>
);
}
...
const Nav = ({ val, nextTitle }) => {
const navData = [
{ id: 0, text: "DOD" },
{ id: 1, text: "analogia" }
];
const length = navData.length;
return (
<nav>
<div>
{/* titles */}
<ul>
<li key="li1">
{navData.map((title, index) => {
return (
<div
className={index === val ? "active" : "display-none"}
key={title.id}
>
{title.text}
</div>
);
})}
</li>
</ul>
{/* chevron button */}
<div>
<button onClick={() => nextTitle(length)}>
<span className="material-icons">chevron_right</span>
</button>
</div>
</div>
</nav>
);
};

Passing value from child to parent, after click event in child (which triggers function)

In <Nav/> component, "click event" on chevron <button>, triggers nextTitle(length) function in useNextTitle.js custom hook. This function sets the value of val, which is being returned by useNextTitle.js. How to pass that new val to App.js ?
Bigger picture: I want to change the display between <Dod /> and <Analogia /> (in App.js), after "click event" in <Nav /> (figured out val would be helpful for that, as a parameter in Conditional Statement).
Functionality I`m trying to achieve is visualized on the website I done with vanilla Java Script : link (the blue navigation, changes "main pages" with "titles" when chevron clicked)
App.js
import Nav from "./components/Nav";
import Dod from "./components/Dod";
import Analogia from "./components/Analogia";
function App() {
return (
<div className="App">
<Nav />
<Dod />
<Analogia />
</div>
);
}
export default App
Nav.js
import useNextTitle from './useNextTitle';
import './Nav.css';
const Nav = () => {
const navData = [
{id: 0, text: "DOD"},
{id: 1, text: "analogia"}
]
const length = navData.length;
const { val, nextTitle } = useNextTitle();
return (
<nav>
<div>
{/* titles */}
<ul>
<li key="li1">
{navData.map((title, index) => {
return (
<div
className={index === val ? "active" : "display-none"} key={title.id}>
{title.text}
</div>
)
})}
</li>
</ul>
{/* chevron button */}
<div>
<button onClick={() => nextTitle(length)}>
<span className="material-icons">
chevron_right
</span>
</button>
</div>
</div>
</nav>
)
}
export default Nav
useNextTitle.js
import { useState } from 'react';
const useNextTitle = () => {
const [val, setVal] = useState(0);
const nextTitle = (length) => {
setVal(val === length -1 ? 0 : val + 1 )
console.log("hook vav = " + val)
}
return { val, nextTitle }
}
export default useNextTitle;
Move the useNextTitle hook/state up to App and pass val and nextTitle down to Nav to toggle/update the state. Use val to conditionally render Dod and Analogia.
Example:
function App() {
const { val, nextTitle } = useNextTitle();
return (
<div className="App">
<Nav {...{ val, nextTitle }} />
{val === 0 && <Dod />}
{val === 1 && <Analogia />}
</div>
);
}
...
const Nav = ({ val, nextTitle }) => {
const navData = [
{ id: 0, text: "DOD" },
{ id: 1, text: "analogia" }
];
const length = navData.length;
return (
<nav>
<div>
{/* titles */}
<ul>
<li key="li1">
{navData.map((title, index) => {
return (
<div
className={index === val ? "active" : "display-none"}
key={title.id}
>
{title.text}
</div>
);
})}
</li>
</ul>
{/* chevron button */}
<div>
<button onClick={() => nextTitle(length)}>
<span className="material-icons">chevron_right</span>
</button>
</div>
</div>
</nav>
);
};

React parent component needs child function to return data

I think I need a call back function, but do not understand the proper syntax given a parent component calling a child function.
Here is the stripped down parent component followed by the function FilesUpload.
I need the File.Name from child returned and setState({fileName}) in parent component.
Hopefully painfully obvious to someone who knows how to do this.
Thank you in advance for solution.
Rob
#davidsz - any ideas?
...
//Stripped down ParentComponent.jsx
import React, { Component } from 'react'
import FilesUpload from "../Services/FilesUpload";
class ParentComponent extends Component {
constructor(props) {
super(props)
this.state = {
fileName: null
}
this.changefileNameHandler = this.changefileNameHandler.bind(this);
}
changefileNameHandler= (event) => {
this.setState({fileName: event.target.value});
}
componentDidMount(){
}
render() {
return (
<div>
<td>this.state.fileName </td>
<FilesUpload onUpdate={this.changefileNameHandler}/>
</div>
)
}
}
export default ParentComponent
//functional service FilesUpload.js
import React, { useState, useEffect, useRef } from "react";
import UploadService from "../Services/FileUploadService";
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
const UploadFiles = () => {
const [selectedFiles, setSelectedFiles] = useState(undefined);
const [progressInfos, setProgressInfos] = useState({ val: [] });
const [message, setMessage] = useState([]);
const [fileInfos, setFileInfos] = useState([]);
const progressInfosRef = useRef(null)
useEffect(() => {
UploadService.getFiles().then((response) => {
setFileInfos(response.data);
});
}, []);
const selectFiles = (event) => {
setSelectedFiles(event.target.files);
setProgressInfos({ val: [] });
};
const upload = (idx, file) => {
let _progressInfos = [...progressInfosRef.current.val];
return UploadService.upload(file, (event) => {
_progressInfos[idx].percentage = Math.round(
(100 * event.loaded) / event.total
);
setProgressInfos({ val: _progressInfos });
})
.then(() => {
toast.info(file.name + " Uploaded")
setMessage((prevMessage) => ([
...prevMessage,
"Uploaded the file successfully: " + file.name,
]));
})
.catch(() => {
_progressInfos[idx].percentage = 0;
setProgressInfos({ val: _progressInfos });
setMessage((prevMessage) => ([
...prevMessage,
"Could not upload the file: " + file.name,
]));
});
};
const uploadFiles = () => {
const files = Array.from(selectedFiles);
let _progressInfos = files.map(file => ({ percentage: 0, fileName: file.name }));
progressInfosRef.current = {
val: _progressInfos,
}
const uploadPromises = files.map((file, i) => upload(i, file));
Promise.all(uploadPromises)
.then(() => UploadService.getFiles())
.then((files) => {
setFileInfos(files.data);
});
setMessage([]);
};
return (
<div>
{progressInfos && progressInfos.val.length > 0 &&
progressInfos.val.map((progressInfo, index) => (
<div className="mb-2" key={index}>
<span>{progressInfo.fileName}</span>
<div className="progress">
<div
className="progress-bar progress-bar-info"
role="progressbar"
aria-valuenow={progressInfo.percentage}
aria-valuemin="0"
aria-valuemax="100"
style={{ width: progressInfo.percentage + "%" }}
>
{progressInfo.percentage}%
</div>
</div>
</div>
))}
<div className="row my-3">
<div className="col-8">
<label className="btn btn-default p-0">
<input type="file" multiple onChange={selectFiles} />
</label>
</div>
<div className="col-4">
<button
className="btn btn-success btn-sm"
disabled={!selectedFiles}
onClick={uploadFiles}
>
Upload
</button>
</div>
</div>
{message.length > 0 && (
<div className="alert alert-secondary" role="alert">
<ul>
{message.map((item, i) => {
return <li key={i}>{item}</li>;
})}
</ul>
</div>
)}
<div className="card">
{/* <div className="card-header">List of Files</div> */}
<ul className="list-group list-group-flush">
{!fileInfos &&
fileInfos.map((file, index) => (
<li className="list-group-item" key={index}>
{/* <a href={file.url}>{file.name}</a> */}
</li>
))}
</ul>
</div>
<ToastContainer position="top-center" autoClose={1000}/>
</div>
);
};
export default UploadFiles;
...
I'm not quite sure I understand your question perfectly, but do you want to pass down the changefileNameHandler function as a prop to your FilesUpload functional component?
In this case you can just add props as a paremeter:
const UploadFiles = (props) => { ...
and call it wherever you need it:
props.onUpdate(event)

How I can resolve this error message in react? Cannot read property 'details' of null

Hello Stackoverflow community!
I'am practicing with react. I am building a very simple shopping cart system. With the app you can select from products. It adds to the shoppingcart. I'm got this error message: TypeError: Cannot read property 'details' of null.
I'am attaching my code.
App.js
import React, {useState, useEffect } from "react";
import Shop from "./Shop";
import Cart from "./Cart"
const ShoppingItems = [{
id: 1,
details: {
type: "cloth",
name: "Blue jacket",
price: 15000
}
},
{
id: 2,
details: {
type: "cloth",
name: "Trousers",
price: 9990
}
},
{
id: 3,
details: {
type: "cloth",
name: "T-shirt",
price: 5000
}
}
];
const App = () => {
const [selectedItem, setSelectedItem] = useState(null);
useEffect(() => {console.log(selectedItem)}, [selectedItem]);
return(
<div className="ui container">
<Shop Shopitems={ShoppingItems} setSelectedItem={setSelectedItem}/>
<Cart selectedItem={selectedItem}/>
</div>
);
};
export default App;
Shop.js
import React from "react";
const Shop = ({Shopitems, setSelectedItem}) => {
const AddItem = (id) => {
const selectedItem = Shopitems.find( item => item.id === id);
if(selectedItem)
{
setSelectedItem(selectedItem);
}
return;
};
const renderedItems = Shopitems.map((shopitem) => {
return(
<div key={shopitem.id} className="card">
<div className="content">
<div className="header">{shopitem.details.name}</div>
<div className="description">
{shopitem.details.price + " Ft"}
</div>
</div>
<div onClick={() => AddItem(shopitem.id)} className="ui bottom attached button">
<i className="cart icon"></i>
Add to cart
</div>
</div>
);
});
return (
<div className="ui cards">{renderedItems}</div>
);
};
export default Shop;
Cart.js
import React, {useState, useEffect} from "react";
const Cart = ({selectedItem}) => {
const [shoppingCart, setShoppingCart] = useState([]);
useEffect(() => {
//Adding to the shopping cart when an element selected
setShoppingCart([...shoppingCart, selectedItem]);
}, [selectedItem]);
const renderedItems = shoppingCart.map((item) => {
return(
<ul>
<li key={item.id}>
<div className="item">
{item.details.name}
</div>
</li>
</ul>
);
});
return(
<div>
<h1>Shopping Cart</h1>
{renderedItems}
</div>
);
};
export default Cart;
You need to verify that selectItem is not null because you cannot use .map on null, it needs to be an array ([]).
change you code to
import logo from './logo.svg';
import './App.css';
import { useEffect, useState } from 'react';
import Records from './Records';
import Shop from "./Shop";
import Cart from "./Cart"
const ShoppingItems = [{
id: 1,
details: {
type: "cloth",
name: "Blue jacket",
price: 15000
}
},
{
id: 2,
details: {
type: "cloth",
name: "Trousers",
price: 9990
}
},
{
id: 3,
details: {
type: "cloth",
name: "T-shirt",
price: 5000
}
}
];
const App = () => {
const [selectedItem, setSelectedItem] = useState(null);
useEffect(() => {console.log(selectedItem)}, [selectedItem]);
return(
<div className="ui container">
{selectedItem !== null ? <><Shop Shopitems={ShoppingItems} setSelectedItem={setSelectedItem}/> <Cart selectedItem={selectedItem}/> </>: <></>}
</div>
);
};
export default App;
This wil render without error but it is blanc page because you pass 'null' as value.
It may not be a value for the first time. To solve this problem, you can bet where you have this error:for example:
const renderedItems = Shopitems?Shopitems.map((shopitem) => {
return(
<div key={shopitem.id} className="card">
<div className="content">
<div className="header">{shopitem.details.name}</div>
<div className="description">
{shopitem.details.price + " Ft"}
</div>
</div>
<div onClick={() => AddItem(shopitem.id)} className="ui bottom attached button">
<i className="cart icon"></i>
Add to cart
</div>
</div>
);
}) :[] ;
return (
<div className="ui cards">{renderedItems}</div>
);
};
export default Shop;
'

Resources