using ternary operator with two map - javascript

I'm trying to learn react by coding, here i have come up with this code which works ! but only i need to know how to use if else or maybe ternary operator here. What i want to achieve is this: when user comes to the page this is already there :
{sisalto.map(({ avain, value }, index) => (
<div>
<div>
<IndexBox y={avain} />
</div>
<div>
<ValueBox value={value} />
</div>
</div>
))}
and when user writes something on input then this comes instead of the first one:
{searchResults.map(({ avain, value }, index) => (
<div>
<div>
<IndexBox y={avain} />
</div>
<div>
<ValueBox value={value} />
</div>
</div>
))}
my code :
function App() {
const [data, setData] = useState([])
const [searchResults, setSearchResults] = useState([])
const [searchTerm, setSearchTerm] = useState('')
const [sisalto, setSisalto] = useState([])
const fetchData = () => {
let corsAnywhere = 'https://cors-anywhere.herokuapp.com/'
let something = 'http://ksngfr.com/something.txt'
fetch(corsAnywhere + something)
.then(response => response.text())
.then(result => {
const theDataArr = result.replace(/\n/g, ' ')
const f = theDataArr.split(' ')
setData(f)
})
}
useEffect(() => {
fetchData()
}, [searchTerm])
useEffect(() => {
const mappedResult = data.map(d => {
var propertyK = d.split(':')[0]
var propertyv = d.split(':')[1]
return {
avain: propertyK,
value: propertyv
}
})
setSisalto(mappedResult)
const results = mappedResult.filter(each => each.avain === searchTerm)
setSearchResults(results)
}, [data, searchTerm])
console.log(sisalto)
return (
<div>
<header>
<div>
<h1>something</h1>
<input
type="text"
value={searchTerm}
placeholder="Search..."
onChange={e => setSearchTerm(e.target.value)}
/>
</div>
</header>
<div>
{searchResults.map(({ avain, value }, index) => (
<div>
<div>
<IndexBox y={avain} />
</div>
<div>
<ValueBox value={value} />
</div>
</div>
))}
</div>
</div>
)
}
export default App
data i'm fetching :
/* ------------------------
2005-07-09 03:05
1:74539
2:29734
3:95426
4:35489
------------------------ */

You can use Ternary Operator like this
<div>
{
isTrue
? (<div>YEP</div>)
: (<div>NO</div>)
}
</div>
Now you can use React.Fragment to achieve your goal like this -
<div>
{
isTrue
? (<React.Fragment>{/* map */}</React.Fragment>)
: (<React.Fragment>{/* map */}</React.Fragment>)
}
</div>
// React.Fragment shorthand
<div>
{
isTrue
? (<>{/* map */}</>)
: (<>{/* map */}</>)
}
</div>
If you don't want anyting in else statement just let it be null like this
{ isTrue ? <>YEP</> : null }

Related

can't map fetched data as an input field autocomplete

I'm trying to capture some suggestions for my input field, i can log them without a problem, but i can't map it and autocomplete on my input type field. trying to understand what i'm doing wrong.
const Lista = () => {
const [search, setSearch] = useState("");
useEffect(() => {
handleSearch();
}, []);
async function handleSearch() {
const response = await fetch("/api/product");
const search = await response.json();
setSearch(search);
console.log(search);
}
if (!search) return <p>Loading</p>;
return (
<>
<section>
<div className="listsContainer">
<div className="cartContainer">
<form className="formContainer" onSubmit={handleSubmit}>
<div className="inputs">
<div>
<label>Product</label>
<input
required
onChange={(e) => setSearch(e.target.value)}
/>
<div>
{search
.filter((item) => {
return search.toLowerCase() === ""
? null
: item.name.toLowerCase().includes(search);
})
.map((item) => (
<div key={item.id}>
<h1>{item.name}</h1>
</div>
))}
</div>
you are mapping 'search' as the response while it contains the user input value.
you should add a new locale state for storing the response and then use it for the mapping.
you should notice that filter is an Array method and will not work on Json. You should filer Object.values(yourJson).
see example bellow:
const Lista = () => {
const [search, setSearch] = useState("");
const [productResponse, setproductResponse] = useState({});
useEffect(() => {
handleSearch();
}, []);
async function handleSearch() {
const response = await fetch("/api/product");
const resToJson= await response.json();
setproductResponse(resToJson);
console.log(resToJson);
}
if (!productResponse) return <p>Loading</p>;
return (
<>
<section>
<div className="listsContainer">
<div className="cartContainer">
<form className="formContainer" onSubmit={handleSubmit}>
<div className="inputs">
<div>
<label>Product</label>
<input
required
onChange={(e) => setSearch(e.target.value)}
/>
<div>
{Object.values(productResponse)?.
.filter((item) => {
return search.toLowerCase() === ""
? null
: item.name.toLowerCase().includes(search);
})

Incorrect validation when trying to send data from additional inputs

Hello everyone and thank you for reading this! Here is my problem that i can't solve:
My application has the following functionality:
There are 2 inputs, then a button, when clicked, 2 more inputs appear and a button to send data from all inputs to the console, however, in the additional field, one input is required. This is where my problem arises: now, if I called additional inputs and filled in all the data, they are transferred to the console, if I didn’t fill in the required field, an error message goes to the console, BUT. I also need, in the event that I did NOT call additional inputs, the data of 2 basic inputs was transferred to the console. At the moment I can't figure it out.
import React, { useState } from "react";
import ReactDOM from "react-dom/client";
import produce from "immer";
const FunctionalBlock = ({
id,
idx,
isDeleted,
toggleBlockState,
additionalValue,
additionalTitle,
setNewBlock,
index,
}) => {
return (
<div
style={{
display: "flex",
maxWidth: "300px",
justifyContent: "space-between",
}}
>
{!isDeleted ? (
<React.Fragment>
<strong>{idx}</strong>
<input
type="text"
value={additionalTitle}
onChange={(e) => {
const additionalTitle = e.target.value;
setNewBlock((currentForm) =>
produce(currentForm, (v) => {
v[index].additionalTitle = additionalTitle;
})
);
}}
/>
<input
type="text"
value={additionalValue}
onChange={(e) => {
const additionalValue = e.target.value;
setNewBlock((currentForm) =>
produce(currentForm, (v) => {
v[index].additionalValue = additionalValue;
})
);
}}
/>
<button onClick={toggleBlockState}>now delete me</button>
</React.Fragment>
) : (
<button onClick={toggleBlockState}>REVIVE BLOCK</button>
)}
</div>
);
};
const Application = () => {
const [newBlock, setNewBlock] = useState([]);
const [firstInput, setFirstInput] = useState("");
const [secondInput, setSecondInput] = useState("");
const getNewBlock = (idx) => ({
id: Date.now(),
idx,
isDeleted: false,
additionalValue: "",
additionalTitle: "",
});
const toggleIsDeletedById = (id, block) => {
if (id !== block.id) return block;
return {
...block,
isDeleted: !block.isDeleted,
};
};
const createOnClick = () => {
const block = getNewBlock(newBlock.length + 1);
setNewBlock([...newBlock, block]);
};
const toggleBlockStateById = (id) => {
setNewBlock(newBlock.map((block) => toggleIsDeletedById(id, block)));
};
const showInputData = () => {
newBlock.map((item) => {
if (item.additionalTitle.length < 3) {
console.log("it is less than 3");
} else if (!item.additionalTitle && !item.additionalValue) {
console.log(firstInput, secondInput);
} else {
console.log(
firstInput,
secondInput,
item.additionalTitle,
item.additionalValue
);
}
});
};
return (
<div>
<div>
<input
type="text"
value={firstInput}
onChange={(e) => {
setFirstInput(e.target.value);
}}
/>
<input
type="text"
value={secondInput}
onChange={(e) => {
setSecondInput(e.target.value);
}}
/>
</div>
<div>
<button onClick={createOnClick}>ADD NEW INPUTS</button>
</div>
<div>
{newBlock.map((block, index) => (
<FunctionalBlock
key={index}
{...block}
toggleBlockState={() => toggleBlockStateById(block.id)}
setNewBlock={setNewBlock}
index={index}
/>
))}
</div>
<button onClick={showInputData}>send data</button>
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Application />);
Here is this code on sandbox for those who decided to help me. Thank you!
https://codesandbox.io/s/vigilant-booth-xnef6t

Wrong document gets updated when using updateDoc from Firebase/Firestore

I use prop drilling to pass down the id value of the document, but every time I click on a document to update it using updateDoc, the same document gets updated(always the latest one added), not the one I clicked on. I don't understand why the unique IDs don't get passed down correctly to the function, or whether that's the problem. I use deleteDoc this way and it's working perfectly. Any help will be appreciated.
This is where I get the id value from
const getPosts = useCallback(async (id) => {
const data = await getDocs(postCollectionRef);
setPosts(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
});
useEffect(() => {
getPosts();
}, [deletePost]);
return (
<div className={classes.home}>
<ul className={classes.list}>
{posts.map((post) => (
<BlogCard
key={post.id}
id={post.id}
title={post.title}
image={post.image}
post={post.post}
date={post.date}
showModal={showModal}
setShowModal={setShowModal}
deletePost={() => {
deletePost(post.id);
}}
showUpdateModal={showUpdateModal}
setShowUpdateModal={setShowUpdateModal}
/>
))}
</ul>
</div>
);
This is where I pass through the id value to the update modal component for each document:
function BlogCard(props) {
const [postIsOpen, setPostIsOpen] = useState(false);
const modalHandler = () => {
props.setShowModal((prevState) => {
return (prevState = !prevState);
});
};
const updateModalHandler = () => {
props.setShowUpdateModal((prevState) => {
return (prevState = !prevState);
});
};
const handleView = () => {
setPostIsOpen((prevState) => {
return (prevState = !prevState);
});
};
return (
<>
{props.showUpdateModal && (
<UpdateModal
showUpdateModal={props.showUpdateModal}
setShowUpdateModal={props.setShowUpdateModal}
id={props.id}
title={props.title}
image={props.image}
post={props.post}
/>
)}
{props.showModal && (
<DeleteModal
showModal={props.showModal}
setShowModal={props.setShowModal}
deletePost={props.deletePost}
/>
)}
<div className={classes.blogCard} id={props.id}>
<div className={classes.head}>
<p className={classes.title}> {props.title}</p>
<div className={classes.buttons}>
<button className={classes.editButton} onClick={updateModalHandler}>
Edit
</button>
<button className={classes.removeButton} onClick={modalHandler}>
Delete
</button>
</div>
</div>
<p className={classes.date}>{props.date}</p>
<img src={props.image} alt="image" />
{!postIsOpen ? (
<p className={classes.viewHandler} onClick={handleView}>
Show More
</p>
) : (
<p className={classes.viewHandler} onClick={handleView}>
Show Less
</p>
)}
{postIsOpen && <p className={classes.article}>{props.post}</p>}
</div>
</>
);
}
export default BlogCard;
Here I create the function to update and add the onclick listener
function UpdateModal(props) {
const [title, setTitle] = useState(props.title);
const [image, setImage] = useState(props.image);
const [post, setPost] = useState(props.post);
const updateModalHandler = (prevState) => {
props.setShowUpdateModal((prevState = !prevState));
};
const updatePost = async (id) => {
const postDocRef = doc(db, "posts", id);
props.setShowUpdateModal(false);
try {
await updateDoc(postDocRef, {
title: title,
image: image,
post: post,
});
} catch (err) {
alert(err);
}
};
return (
<div onClick={updateModalHandler} className={classes.backdrop}>
<form onClick={(e) => e.stopPropagation()} className={classes.form}>
<label htmlFor="title">Title</label>
<input
id="title"
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<label htmlFor="image">Image(URL)</label>
<input
id="image"
type="text"
value={image}
onChange={(e) => setImage(e.target.value)}
/>
<label htmlFor="post">Post</label>
<textarea
id="post"
cols="30"
rows="30"
value={post}
onChange={(e) => setPost(e.target.value)}
/>
<div className={classes.buttons}>
<button className={classes.cancel} onClick={updateModalHandler}>Cancel</button>
<button className={classes.update} onClick={() => updatePost(props.id)}>Update</button>
</div>
</form>
</div>
);
}
export default UpdateModal;
This is the way my data is structured
firebase

Issue Removing specific React jsx element from list of elements

first time asking questions haha, I'm trying to remove a specific JSX element from my array of elements but I am not sure how to identify said element is the one being clicked to get removed so I wanted to know if anyone encountered this issue before and how you would go about solving it.
This is the code for the input Container
const InputComponent = (props) => {
return (
<div className="input-container" onClick={e =>console.log(e)}>
<input className="input-name" type="text" />
<input className="input-value" type="text" />
<button className="remove-button" onClick={props.remove}><img src={minusIcon} alt="remove-icon" /></button>
</div>
);
}
export default InputComponent;
and this is the code for the parent component to manage the removal of said element
const Main = () => {
const [newInput, setInput] = useState([]);
const [currentInput, setCurrentInput] = useState([<InputComponent key={0}/>]);
const [currentIndex, setIndex] = useState(0)
const [currentPlanName, setCurrentPlanName] = useState('Current-Plan');
const [newPlanName, setNewPlanName] = useState('New-Plan');
// const [currentInputValue, setCurrentValue] = useState('')
// const [newInputValue, setNewValue] = useState('')
// Sets Keys for each New Element in Array
const [newKey, setNewKey] = useState(0);
const [currentKey, setCurrentKey] = useState(0)
// Handle Removal of specific array by using key
const handleCurrentRemoval = () => {
let newArray = currentInput.filter(element => element.key !== )
console.log(newArray)
setCurrentInput(newArray)
}
// Initialize Keys for each Array
const currentArrayElement = {
element: <InputComponent key={currentKey} remove={handleCurrentRemoval} />,
index: currentKey
};
const newArrayElement = <InputComponent key={newKey+1}/>
// Adds new Element to array
const handleCurrentClick = () => {
setCurrentInput(prevValues => [...prevValues, currentArrayElement.element])
setCurrentKey(currentKey+1);
console.log(currentArrayElement)
console.log(currentInput)
};
const handleNewClick = () => {
setInput(prevValues => [...prevValues, newArrayElement])
};
// const handleRemoveClick = (value) => {
// currentInput.filter(current => value !=)
// }
return (
<div className="main-container">
<div className="quote-container">
<div className="current-plan">
<h2>{currentPlanName}</h2>
{
currentInput.map((inputs) => {
return inputs
})
}
<div className="button-container">
<button className="add-input" onClick={handleCurrentClick}><img src={addIcon} alt="add"/></button>
</div>
</div>
<div className="new-plan">
<h2>{newPlanName}</h2>
{
newInput.map((inputs) => {
return inputs
})
}
<div className="button-container">
<button className="add-input" onClick={handleNewClick}><img src={addIcon} alt="add"/></button>
</div>
</div>
</div>
</div>
);
}
export default Main;
I do apologize in advance if I posted this incorrectly.
Thank you for your assistance
I think you've made this entirely more complex than it needs to be with all the index value storage in state. It is also anti-pattern in React to store JSX in state, you should store data in state and render the data to JSX.
I suggest storing generated input ids in the arrays instead and mapping these to JSX.
Example:
// id generator
let id = 0;
const getId = () => id++;
export default function App() {
const [newInput, setInput] = useState([]);
const [currentInput, setCurrentInput] = useState([]);
const [currentPlanName, setCurrentPlanName] = useState("Current-Plan");
const [newPlanName, setNewPlanName] = useState("New-Plan");
// Handle Removal of specific element by using id
const handleCurrentRemoval = (removeId) => {
setCurrentInput((ids) => ids.filter((id) => id !== removeId));
};
// Adds new id to array
const handleCurrentClick = () => {
setCurrentInput((ids) => ids.concat(getId()));
};
const handleNewClick = () => {
setInput((ids) => ids.concat(getId()));
};
const handleRemoveClick = (removeId) => {
setInput((ids) => ids.filter((id) => id !== removeId));
};
return (
<div className="main-container">
<div className="quote-container">
<div className="current-plan">
<h2>{currentPlanName}</h2>
{currentInput.map((id) => {
return (
<InputComponent
key={id}
remove={() => handleCurrentRemoval(id)}
/>
);
})}
<div className="button-container">
<button className="add-input" onClick={handleCurrentClick}>
<img src={addIcon} alt="add" />
</button>
</div>
</div>
<div className="new-plan">
<h2>{newPlanName}</h2>
{newInput.map((id) => {
return (
<InputComponent key={id} remove={() => handleRemoveClick(id)} />
);
})}
<div className="button-container">
<button className="add-input" onClick={handleNewClick}>
<img src={addIcon} alt="add" />
</button>
</div>
</div>
</div>
</div>
);
}

react update state from children broke component at the same level

I am new to react. I'm trying to update the parent state from the child but i have an error on another component at the the same level of the child one.
that's my code.
RedirectPage.js (parent)
const RedirectPage = (props) => {
const [status, setStatus] = useState("Loading");
const [weather, setWeather] = useState(null);
const [location, setLocation] = useState(null)
const [showLoader, setShowLoader] = useState(true)
const [userId, setUserId] = useState(false)
const [isPlaylistCreated, setIsPlaylistCreated] = useState(false)
const headers = getParamValues(props.location.hash)
const getWeather = () =>{
//fetch data..
//...
//...
.then(response => {
var res = response.json();
return res;
})
.then(result => {
setWeather(result)
setShowLoader(false)
setStatus(null)
setLocation(result.name)
});
})
}
const changeStateFromChild = (value) => {
setIsPlaylistCreated(value)
}
useEffect(() => {
getWeather()
},[]);
return (
<div className="containerRedirectPage">
{showLoader ? (
<div className="wrapperLogo">
<img src={loader}className="" alt="logo" />
</div>)
: (
<div className="wrapperColonne">
<div className="firstRow">
<WeatherCard weatherConditions={weather}/>
</div>
{isPlaylistCreated ? (
<div className="secondRow">
<PlaylistCard />
</div>
) : (
<PlaylistButton userId={userId} headers={headers} weatherInfo={weather} playlistCreated={changeStateFromChild} />
)}
</div>
)}
</div>
)
};
export default RedirectPage;
PlaylistButton.js:
export default function PlaylistButton({userId, headers, weatherInfo, playlistCreated}) {
const buttonClicked = async () => {
// ...some code...
playlistCreated(true)
}
return (
<div className="button-container-1">
<span className="mas">CREA PLAYLIST</span>
<button onClick={buttonClicked} id='work' type="button" name="Hover">CREA PLAYLIST</button>
</div>
)
}
and that's the other component i'm getting the error when i click on button.
WeatherCard.js:
const WeatherCard = ({weatherConditions}) => {
const [weather, setWeather] = useState(null);
const [icon, setIcon] = useState(null);
const getTheIcon = () => {
// code to get the right icon
}
setIcon(x)
}
useEffect(() => {
getTheIcon()
},[]);
return (
<div className="weatherCard">
<div className="headerCard">
<h2>{weatherConditions.name}</h2>
<h3>{Math.floor(weatherConditions.main.temp)}°C</h3>
</div>
<div className="bodyCard">
<h5>{weatherConditions.weather[0].description}</h5>
<img className="weatherIcon" src={icon} alt="aa" />
</div>
</div>
)
};
export default WeatherCard;
the first time i load the redirect page WeatherCard component is right. When i click the button i get this error:
error
Can someone explain me why ?
What is the effect of the setting playlistCreated(true) ?
Does it affects the weatherCondition object ?
If weatherCondition could be undefined at some point you need to check it before using its properties (name, main.temp, and weather)
Update:
The error clearly state that it cannot read name from weather because it's undefined. You have to check it before using the weather object properties.
if (!weatherConditions) {
return <div>Loading...</div> // or something appropriate.
}
return (
<div className="weatherCard">
<div className="headerCard">
<h2>{weatherConditions.name}</h2>
{weatherConditions.main && <h3>{Math.floor(weatherConditions.main.temp)}°C</h3>}
</div>
<div className="bodyCard">
{weatherConditions.weather &&
{weatherConditions.weather.length > 0 &&
<h5>{weatherConditions.weather[0].description}</h5>}
....
)

Categories

Resources