React- pass {selected, setSelected} as a object props to component? - javascript

I'm learning how to do dropdown menu from a tutorial.
There are some parts that I don't know..
why pass {selected, setSelected} as a object props to Dropdown component instead of using selected, setSletected directly? I've tried and it throws an error.
at this part
{options.map((option) => (
<div
onClick={(e) => {
setSelected(option);
}}
>
the tutorial initially
used onClick={(e) => {setSelected(e.target.textContent);}}
why have to change e.target.textContent into option?
how do program know which item is selected exactly by option without using e.target.textContent?
function App() {
const [selected, setSelected] = React.useState("Choose One");
return (
<div>
{/* custom dropdown menu */}
<Dropdown selected={selected} setSelected={setSelected} />
{selected}
</div>
);
}
function Dropdown({ selected, setSelected }) {
const [isActive, setIsActive] = React.useState(false);
const options = ["React", "Vue", "Angular"];
return (
<div onClick={(e) => setIsActive(!isActive)}>
{isActive && (
<div>
{options.map((option) => (
<div
onClick={(e) => {
setSelected(option);
}}
></div>
))}
</div>
)}
</div>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Related

<li> elements missing keys even after assigning unique keys to each element (ReactJS) [duplicate]

I am a beginner at React. I wrote this code and got an Error
import { DoItem } from '../MyComponents/DoItem'
export const ToDo = (props) => {
return (
<div className="container">
<h3 className="text-center">To Do List</h3>
{props.todos.map((todo) => {
return (
<>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</>
)
})}
</div>
)
}
Here's the error Each child in a list should have a unique "key" prop.
I looked online and found that I have to use a key.
I inserted the key
<DoItem const todo={todo} key={todo.nos} onDelete = {props.onDelete} />
But the error still didn't go after I reload the page.
Please add a unique key to every item
{props.todos.map((todo, index) => {
return (
<div key={index}>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</div>
)
})}
Please have a try and let me know if it works or not.
import { DoItem } from '../MyComponents/DoItem'
export const ToDo = (props) => {
return (
<div className="container">
<h3 className="text-center">To Do List</h3>
{props.todos.map((todo, i) => {
return (
<key={i}>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</>
)
})}
</div>
)
}
Yeah, you should add a key prop to anytime you're rendering an Array.
import { DoItem } from '../MyComponents/DoItem'
export const ToDo = (props) => {
return (
<div className="container">
<h3 className="text-center">To Do List</h3>
{props.todos.map((todo,index) => {
return (
<div key={index | the id of the todo}>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</div>
)
})}
</div>
)
}

How to change react icons while clicking it?

I have some icons from react-icons that I want to change from outline to filled whenever I click it but instead of changing itself, it changes all the icons from outline to filled.
Here is my code
function Header() {
const [isActive, setIsActive] = useState(false);
return (
....
<div className="flex items-center space-x-6">
<div className="cursor-pointer select-none">
{isActive? <AiOutlineHome onClick={()=>{
setIsActive(!isActive)}}/>:
<AiFillHome onClick={()=>{
setIsActive(!isActive)}} />
}
</div>
<div className="cursor-pointer select-none">
{isActive?<MdOutlineAddBox onClick={()=>{
setIsActive(!isActive)}}/>:
<MdAddBox onClick={()=>{
setIsActive(!isActive)}} />}
</div>
....
)}
I know it's because they are sharing the same isActive state, but I don't know exactly how to fix it. Can someone please help me with this?
Edit:
function HeaderIcon({ Icon, ActiveIcon }) {
const [isActive, setIsActive] = useState(false);
return (
<div>{isActive ? <Icon /> : <ActiveIcon />}</div>
);
}
export default HeaderIcon;
I put this component in a new file but how can I pass the onClick to it?
You need to use two different state
function Header() {
const [isActive, setIsActive] = useState(false);
const [isActive2, setIsActive2] = useState(false);
return (
....
<div className="flex items-center space-x-6">
<div className="cursor-pointer select-none">
{isActive? <AiOutlineHome onClick={()=>{
setIsActive(!isActive)}}/>:
<AiFillHome onClick={()=>{
setIsActive(!isActive)}} />
}
</div>
<div className="cursor-pointer select-none">
{isActive2?<MdOutlineAddBox onClick={()=>{
setIsActive2(!isActive2)}}/>:
<MdAddBox onClick={()=>{
setIsActive2(!isActive2)}} />}
</div>
....
)}
I hope this will do magic
The answer for this is:
import React, { useState } from "react";
function HeaderIcon({ inactiveIcon, activeIcon }) {
const [isActive, setIsActive] = useState(false);
return (
<div onClick={() => setIsActive(!isActive)}>
{isActive ? activeIcon : inactiveIcon}
</div>
);
}
export default HeaderIcon;
Then pass in the icon you want.

React Error: Each child in a list should have a unique "key" prop

I am a beginner at React. I wrote this code and got an Error
import { DoItem } from '../MyComponents/DoItem'
export const ToDo = (props) => {
return (
<div className="container">
<h3 className="text-center">To Do List</h3>
{props.todos.map((todo) => {
return (
<>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</>
)
})}
</div>
)
}
Here's the error Each child in a list should have a unique "key" prop.
I looked online and found that I have to use a key.
I inserted the key
<DoItem const todo={todo} key={todo.nos} onDelete = {props.onDelete} />
But the error still didn't go after I reload the page.
Please add a unique key to every item
{props.todos.map((todo, index) => {
return (
<div key={index}>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</div>
)
})}
Please have a try and let me know if it works or not.
import { DoItem } from '../MyComponents/DoItem'
export const ToDo = (props) => {
return (
<div className="container">
<h3 className="text-center">To Do List</h3>
{props.todos.map((todo, i) => {
return (
<key={i}>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</>
)
})}
</div>
)
}
Yeah, you should add a key prop to anytime you're rendering an Array.
import { DoItem } from '../MyComponents/DoItem'
export const ToDo = (props) => {
return (
<div className="container">
<h3 className="text-center">To Do List</h3>
{props.todos.map((todo,index) => {
return (
<div key={index | the id of the todo}>
<DoItem const todo={todo} onDelete = {props.onDelete} />
<hr />
</div>
)
})}
</div>
)
}

unable to access custom component property from parent component

I have created one custom component, alternative of Select component, on click shows ul and on click hide ul.
when I click I can set value to the state inside function, but i want to access the value in parent component.
so my component is
const [showMenu, setShowMenu] = useState(false);
const [value, setValue] = useState();
return (
<>
<button
className='btn'
onClick={() =>
showMenu ? setShowMenu(false) : setShowMenu(true)
}>
{props.name}
</button>
<ul className={showMenu ? "" : "hide"}>
{props.listsa.map((element) => {
return (
<li
key={element.key}
value={element.value}
onClick={(e) => {
setValue(e.target.value);
}}>
{element.label}
</li>
);
})}
</ul>
</>
I want to access value mentioned above functional component in parent component, which is my app.js
as shown below, this is return method of parent component.
<div className='App'>
{/* <Main /> */}
<OptionsComponent name='ABC Menu' listsa={abc} />
{/* here I want to use that value to perfom operations/ also on change it should show changed value */}
</div>
I tried using localStorage.setItem("value":value) it works but that will use browser memory so I am looking for alternative way.
I tried exporting variable, it shows undefined, also I tried making varibale global, it works but doesnt reflect change.
any help will be appreciated
You just need to bring the state up and pass it down, instead:
const [value, setValue] = useState();
return (
<div className='App'>
{/* <Main /> */}
<OptionsComponent name='ABC Menu' listsa={abc} value={value} setValue={setValue}/>
</div>
And
const [showMenu, setShowMenu] = useState(false);
return (
<>
<button
className='btn'
onClick={() =>
showMenu ? setShowMenu(false) : setShowMenu(true)
}>
{props.name}
</button>
<ul className={showMenu ? "" : "hide"}>
{props.listsa.map((element) => {
return (
<li
key={element.key}
value={element.value}
onClick={(e) => {
props.setValue(e.target.value);
}}>
{element.label}
</li>
);
})}
</ul>
</>
);

Add additional props to JSX Element variable

How can I add additional props to a JSX.Element variable that is passed as a prop?
First I create the variable like so
const leftIcon = <SmallIcon icon="note" color={colors.red} />
Then it is passed to my function component and used like
const ScreenHeader: React.FunctionComponent<ScreenHeaderProps> = ({
leftIcon = <></>,
}) => {
return (
<View>
<Header
leftComponent={leftIcon}
/>
</View>
)};
How can I add an additional styles prop to the "leftIcon" variable before it is used in Header?
If you initialize a variable with a React component the way you're doing it right now (const leftIcon = <SmallIcon />), then you won't be able to pass additional props into it.
Here's a possible solution:
// make `LeftIcon` into a function so that you
// can use it in the following way: `<LeftIcon />`
const LeftIcon = (props) => (
<div className="LeftIcon" onClick={() => {}} {...props}>
<p>I am a left icon!</p>
<p>Additional props: {JSON.stringify(props)}</p>
</div>
);
const ScreenHeader = ({ leftComponent = null }) => {
const CustomLeftComponent = leftComponent ? leftComponent : null;
const greenComponent = CustomLeftComponent
? <CustomLeftComponent style={{ color: "green" }} />
: null;
return (
<div>
<p>I am a screen header!</p>
{greenComponent}
</div>
);
};
function App() {
return (
<div className="App">
<ScreenHeader leftComponent={LeftIcon} />
<hr />
<ScreenHeader />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById("app")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Alternatively, you could pass additional props to the LeftIcon component prior to using it inside ScreenHeader:
// make `LeftIcon` into a function so that you
// can use it in the following way: `<LeftIcon />`
const LeftIcon = (props) => (
<div className="LeftIcon" onClick={() => {}} {...props}>
<p>I am a left icon!</p>
<p>Additional props: {JSON.stringify(props)}</p>
</div>
);
const ScreenHeader = ({ leftComponent = null }) => {
return (
<div>
<p>I am a screen header!</p>
{leftComponent}
</div>
);
};
function App() {
return (
<div className="App">
<ScreenHeader leftComponent={<LeftIcon style={{ color: "green" }} />} />
<hr />
<ScreenHeader />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById("app")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
You can use React.cloneElement to add additional props
const ScreenHeader: React.FunctionComponent<ScreenHeaderProps> = ({
leftIcon = <></>,
}) => {
return (
<View>
<Header
leftComponent={React.cloneElement(leftIcon, {className: classes.myClass})}
/>
</View>
)};

Categories