I am having a hard time rendering components conditionally in React. I have successfully rendered 2 components (A and B) conditionally but couldn't find any successful way to add a third component (C) in our case
this is the code for 2 componnets:
function App() {
const [click, setClick] = useState(true);
const ShowA = () => setClick(true);
const ShowB = () => setClick(false);
return (
<>
<br />
<button onClick={ShowA}>A </button>
<button onClick={ShowB}>B </button>
<div className="App">
{click && <div> A </div>}
{!click && <div>B</div>}
</div>
</>
);
}
Is there any possible way I can add a third C component so I can toggle between them? I have been trying for 2 days but no success.
This is the link of Codesandbox if anyone's interested
https://codesandbox.io/s/musing-tesla-9gkpw?file=/src/index.js:100-481
You can put as many states as you want:
function App() {
const [displayA, setDisplayA] = useState(true);
const [displayB, setDisplayB] = useState(true);
const [displayC, setDisplayC] = useState(true);
const showA = () => {
setDisplayA(true);
setDisplayB(false);
setDisplayC(false);
}
const showB = () => {
setDisplayA(false);
setDisplayB(true);
setDisplayC(false);
};
const showC = () => {
setDisplayA(false);
setDisplayB(false);
setDisplayC(true);
};
return (
<>
<br />
<button onClick={showA}>A</button>
<button onClick={showB}>B</button>
<button onClick={showC}>C</button>
<div className="App">
{displayA && <div>A</div>}
{displayB && <div>B</div>}
{displayC && <div>C</div>}
</div>
</>
);
}
And you can even put other things in your state, like JSX elements:
function App() {
const [elementToDisplay, setElementToDisplay] = useState("");
const showA = () => {
setElementToDisplay(<div>A</div>)
}
const showB = () => {
setElementToDisplay(<div>B</div>)
}
const showC = () => {
setElementToDisplay(<div>C</div>)
}
return (
<>
<br />
<button onClick={showA}>A</button>
<button onClick={showB}>B</button>
<button onClick={showC}>C</button>
<div className="App">
{elementToDisplay}
</div>
</>
);
}
You can save a state for the current button, and then show the different button conditionally using object lookup:
Check https://codesandbox.io/s/kind-haslett-b0fv0
function App() {
const [currentButton, setCurrentButton] = useState('A');
return (
<>
<br />
<button onClick={() => setCurrentButton('A')}>A</button>
<button onClick={() => setCurrentButton('B')}>B</button>
<button onClick={() => setCurrentButton('C')}>C</button>
<div className="App">
{
({
A: <div>A</div>,
B: <div>B</div>,
C: <div>C</div>
})[currentButton]
}
</div>
</>
);
}
Related
I have a very basic react component like this
const Message = (props) => {
const [show, setShow] = useState(false);
return (
<p show={show}>My Message</p>
);
};
I want to use this component from another one, and I want to be able to show the first one by clicking on a button in the second one
const OtherComponent = (props) => {
return (
<>
<Message />
<Button onClick={setShow(true)}>Open Message</Button>
</>
);
};
of course this code does not work, is there a way to achieve this or is Redux my only option?
Move state to parent
const Message = ({ show }) => {
return (
<p show={show}>My Message</p>
);
};
const OtherComponent = (props) => {
const [show, setShow] = useState(false);
return (
<>
<Message show={show} />
<Button onClick={setShow(true)}>Open Message</Button>
</>
);
};
When editing a todo it will automictically clear the value, I would like it to contain its original value so you can edit upon it rather than typing everything all over again.
Im assuming usestate is setting the editingText into an empty string in which case in will always output a empty value?
Also I would like to incorporate a cancel button in which cancels eiditing and returns back to its current value.
const App = () => {
const [todos, setTodos] = React.useState([]);
const [todo, setTodo] = React.useState("");
const [todoEditing, setTodoEditing] = React.useState(null);
const [editingText, setEditingText] = React.useState("");
function handleSubmit(e) {
e.preventDefault();
const newTodo = {
id: new Date().getTime(),
text: todo,
completed: false,
};
setTodos([...todos].concat(newTodo));
setTodo("");
}
function deleteTodo(id) {
let updatedTodos = [...todos].filter((todo) => todo.id !== id);
setTodos(updatedTodos);
}
function toggleComplete(id) {
let updatedTodos = [...todos].map((todo) => {
if (todo.id === id) {
todo.completed = !todo.completed;
}
return todo;
});
setTodos(updatedTodos);
}
function submitEdits(id) {
const updatedTodos = [...todos].map((todo) => {
if (todo.id === id) {
todo.text = editingText;
}
return todo;
});
setTodos(updatedTodos);
setTodoEditing(null);
}
return (
<div id="todo-list">
<h1>Todo List</h1>
<form onSubmit={handleSubmit}>
<input
type="text"
onChange={(e) => setTodo(e.target.value)}
value={todo}
/>
<button type="submit">Add Todo</button>
</form>
{todos.map((todo) => (
<div key={todo.id} className="todo">
<div className="todo-text">
{todo.id === todoEditing ? (
<input
type="text"
onChange={(e) => setEditingText(e.target.value)}
/>
) : (
<div>{todo.text}</div>
)}
</div>
<div className="todo-actions">
{todo.id === todoEditing ? (
<button onClick={() => submitEdits(todo.id)}>Submit Edits</button>
) : (
<button onClick={() => setTodoEditing(todo.id)}>Edit</button>
)}
<button onClick={() => deleteTodo(todo.id)}>Delete</button>
</div>
</div>
))}
</div>
);
};
export default App;
Use defaultValue to set the initial value of the input
<div className="todo-text">
{todo.id === todoEditing ? (
<input
defaultValue={todo.text}
type="text"
onChange={(e) => setEditingText(e.target.value)}
/>
) : (
<div>{todo.text}</div>
)}
</div>
Adding a cancel button is just setting your edit id to null
<>
<button onClick={() => submitEdits(todo.id)}>
Submit Edits
</button>
<button onClick={() => setTodoEditing(null)}>Cancel</button>
</>
Stackblitz: https://stackblitz.com/edit/react-ts-rarpqn?file=App.tsx
Use value prop
{todo.id === todoEditing ? (
<input
value={todo.text}
type="text"
onChange={(e) => setEditingText(e.target.value)}
/>
) : (
<div>{todo.text}</div>
)}
I clicked the Button and executed the onClickUserId function.
Then, if I run this function, I want to run the onClickListContent Button function as well.
I don't know what to do.
I want to display the argument value in the console.log so that onClickListContent is automatically clicked when the onClickUserId value is clicked.
const onClickUserId = (id) => {
console.log(id)
}
const onClickListContent = (Content) => {
console.log(Content);
};
return (
<div>
<>
<div>
<button onClick={() => onClickUserId(3)}>click</button>
</div>
</>
<>
<div>
<button onClick={() => onClickListContent(6)}>click</button>
</div>
</>
</div>
)
I tried to put the onClickListContent.click() function in the onClickUserId function, but it cannot be executed because of the argument value.
How should I write the code?
import {useRef} from 'react'
export default function App() {
const ref = useRef()
const onClickUserId = (id) => {
console.log(id);
ref.current.click();
};
const onClickListContent = (Content) => {
console.log(Content);
};
return (
<div>
<>
<div>
<button onClick={() => onClickUserId(3)}>click</button>
</div>
</>
<>
<div>
<button ref={ref} onClick={() => onClickListContent(6)}>click</button>
</div>
</>
</div>
);
}
you can create a reference to that button and use it trigger the click function.
use react useRef() hook:
const listContentBtn = useRef(null);
const onClickUserId = (id) => {
console.log(id)
listContentBtn.current.click()
}
const onClickListContent = (Content) => {
console.log(Content);
};
return (
<div>
<>
<div>
<button onClick={() => onClickUserId(3)}>click</button>
</div>
</>
<>
<div>
<button onClick={() => onClickListContent(6)} ref={listContentBtn}>click</button>
</div>
</>
</div>
)
counterScreen.js
import React, { useState } from "react";
const CounterScreen = () => {
const [count, setCount] = useState(0);
return (
<div>
<h2>This the number: {count}</h2>
</div>
) }
export default CounterScreen
addButton.js
import React from 'react'
const AddButton = () => {
return (
<div>
<button>+</button>
</div>
) }
export default AddButton
subtractButton.js
import React from 'react'
const SubtractButton = () => {
return (
<div>
<button>-</button>
</div>
) }
export default SubtractButton
i want when i click the button in addbutton.js the counter should add 1 and when i click the button in subtractbutton.js the counter should subtract 1
what will be the best way to share the state here please help
One simple way to solve this is to put the state in the containing component, and pass in values or callbacks to the relevant components:
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<CounterScreen count={count}/>
<AddButton onClick={() => setCount(count+1)}/>
<SubtractButton onClick={() => setCount(count-1)}/>
</div>
);
};
const CounterScreen = ({count}) => {
return (
<div>
<h2>This the number: {count}</h2>
</div>
)
};
const AddButton = ({onClick}) => {
return (
<div>
<button onClick={onClick}>+</button>
</div>
)
};
const SubtractButton = ({onClick}) => {
return (
<div>
<button onClick={onClick}>-</button>
</div>
)
};
I'm new in React, I don't know what keyword to find my solution. I have many <button> and just want to toggle the button that got clicked. How to achieve that?
Here's what i've been trying...
export default function App() {
const [text, setText] = useState(false);
const btnText = text ? 'Foo' : 'Bar';
const handleClick = () => setText((prevState) => !prevState);
return (
<div className="App">
<button type="button" onClick={handleClick}>{btnText}</button>
<button type="button" onClick={handleClick}>{btnText}</button>
<button type="button" onClick={handleClick}>{btnText}</button>
</div>
);
}
Add unique id on each buttons, and you can change your code like this:
export default function App() {
const listOfButtons = [0, 1, 2];
const [btnClicked, setBtnClicked] = useState([]);
const handleClick = (id) => setBtnClicked({...btnClicked, [id]: !btnClicked[id]});
return (
<div className="App">
{listOfButtons.map(id => (
<button type="button" onClick={() => handleClick(id)}>{`${btnClicked[id] ? 'clicked' : 'not clicked'}`}</button>
))}
</div>
);
}
When you pass a function without the parens, you're just passing the definition. In your onClick, invoke your function like this:
onClick={()=>handleClick()}
if you were to invoke the handleClick function w/o it being inside an arrow function, then you would get an infinite loop.
onClick={handleClick()}
export default function App() {
//each button needs its own state
const [text, setText] = React.useState({
button234423: false,
button456645: false,
button398375: false
});
//target button in state by element id
const handleClick = e => {
const id = e.target.id;
setText(text => ({ ...text, [id]: !text[id] }));
};
//map state to return button element with key as id and value as conditional
return (
<div className="App">
{Object.entries(text).map(([key, value]) => {
return (
<button type="button" key={key} id={key} onClick={handleClick}>
{value ? "Foo" : "Bar"}
</button>
);
})}
</div>
);
}
Currently state shared to all the button. Keep it as a separate component
import './App.css';
function App() {
return (
<div className="App">
<Button />
<Button />
<Button />
</div>
);
}
export const Button = () => {
const [text, setText] = useState(false);
const btnText = text ? 'Foo' : 'Bar';
const handleClick = () => setText((prevState) => !prevState);
return <button type="button" onClick={handleClick}>{btnText}</button>
}
export default App;