I'm new to React.js.
and I tried to use a function that has boolean, and I want to reuse just one function to another button.
so I tried like this:
function App() {
const [show, setShow] = useState(false);
const [show1, setShow1] = useState(false);
const [show2, setShow2] = useState(false);
const handleOnClick = () => {
setShow(true);
setShow1(false);
setShow2(false);
};
const handleOnClick1 = () => {
setShow1(true);
setShow(false);
setShow2(false);
};
const handleOnClick2 = () => {
setShow2(true);
setShow(false);
setShow1(false);
};
const panels = ["1+3", "2+2", "3+1"];
const getPanel = e => {
switch (e) {
case "1+3":
handleOnClick();
break;
case "2+2":
handleOnClick1();
break;
case "3+1":
handleOnClick2();
break;
default:
break;
}
};
const panelList = panels.map(panel => (
<div onClick={() => getPanel(panel)}>
<h1>Panel{panel}</h1>
</div>
));
return (
<div>
<Main>{panelList}</Main>
{show && <One />}
{show1 && <Two />}
{show2 && <Three />}
</div>
the question is
How can i use one useState instead of making another one ??
If you're always just going to have one button showing, you can go ahead and just maintain the ID of that button in state rather than a bunch of boolean states.
Furthermore, it might be nice to make just one click handler. You could do this a bunch of ways, such as using the clicked button's ID, or you could do a higher-order function and pass the clicked ID directly. Here is the latter approach:
function App() {
const [show, setShow] = useState();
const handleOnClick = (id) => () => {
setShow(id);
}
return (
<>
<button onClick={handleClick(1)}>Show 1</button>
<button onClick={handleClick(2)}>Show 2</button>
<button onClick={handleClick(3)}>Show 3</button>
{show === 1 && <One />}
{show === 2 && <Two />}
{show === 3 && <Three />}
</>
);
}
Related
I have some code that looks like this
const Movies = () => {
const [show, setShow] = useState(false);
const [show1, setShow1] = useState(false);
const onClick = () => setShow(!show);
const onClick1 = () => setShow1(!show1);
return (
<div className="movie">
<Header />
<h2>Discover a new movie!</h2>
<div className="showBtns">
<button onClick={onClick} className="right">Search <FaSearch /></button>
<button onClick={onClick1}>Discover <FaSearch /></button>
</div>
{show1 ? <DropDown /> : null }
{show ? <MovieSearch /> : null }
<Nav />
</div>
);
};
as of right now if I click on the button for either one it will show the corresponding component but if both are clicked they both show up.
I'd like to write an if else statement to check if one is showing then the other should not be shown.
I've tried a few different things and can't seem to get it to work.
any feedback on a better way to do this or how to get it to work would be appreciated.
if(show === true){
setShow1(false)
} else if(show1 === true) {
setShow(false)
}
this gives an error of Too many re-renders. React limits the number of renders to prevent an infinite loop.
You can handle the hiding/showing logic for these button in the click events because that is where the state changes.
Example:
https://codesandbox.io/s/wild-water-f5nzor?file=/src/App.js
You can modify your onClick functions like this:
const onClick = () => setShow((prevState) => !show1 && !prevState); const onClick1 = () => setShow1((prevState) => !show && !prevState);
I am making a calculator using react.
Every time I press a number button, the whole application re-renders, instead of the <Display />.
To prevent it, I tried 2 different approaches for App, But neither of them worked.
Here is the sandbox link.
Any help would be appreciated.
Put clickHandler inside of useCallback()
const App = () => {
const [screen, setScreen] = useState("0");
console.log("render");
const clickHandler = useCallback(
(val) => {
if (val === "AC") {
setScreen("");
return;
}
screen === "0" ? setScreen(val) : setScreen(screen + val);
},
[screen]
);
return (
<div className="App">
<div className="display">{screen}</div>
<ButtonList clickHandler={clickHandler} />
</div>
);
};
Put Display component inside of React.memo
const App = () => {
const [screen, setScreen] = useState("0");
console.log("render");
const clickHandler = (val) => {
if (val === "AC") {
setScreen("");
return;
}
screen === "0" ? setScreen(val) : setScreen(screen + val);
};
const displayComponent = () => {
return (
<>
<div className="display">{screen}</div>
<ButtonList clickHandler={clickHandler} />
</>
);
};
const MemoizedComponent = React.memo(displayComponent);
return (
<div className="App">
<MemoizedComponent />
</div>
);
};
And here's the ButtonList & Button component.
export const ButtonList = ({ clickHandler }) => {
const arr = [...Array.from(Array(10).keys()).reverse(), "AC"];
return (
<div className="buttons">
<div className="numbersWrapper">
{arr.map((item) => (
<Button
key={item}
clickHandler={clickHandler}
value={item.toString()}
/>
))}
</div>
</div>
);
};
export const Button = ({ value, clickHandler }) => {
return (
<button
name={value}
onClick={() => {
clickHandler(value); //where the clickEvent happens
}}
>
{value}
</button>
);
};
If you don't want a component re-render,You would have to define the click handler in another component that you would like to re-render.
So do it like this:
const App = () => {
console.log("render");
return (
<div className="App">
<childComponent />
</div>
);
};
export const childComponent = () => {
const [screen, setScreen] = useState("0");
const clickHandler = (val) => {
if (val === "AC") {
setScreen("");
return;
}
screen === "0" ? setScreen(val) : setScreen(screen + val);
};
return (
<>
<div className="display">{screen}</div>
<ButtonList clickHandler={clickHandler} />
</>
);
}
This way you prevent a particular component from re-rendering. But note that if you update a state or do anything from which causes re-renders from the parent component, It would equally re-render the child component.
I'm finding I'm having to duplicate the same function over again when I could write one function that handles different parameters. I can't get it to work so I wondered if someone could point me in the right direction? Below shows only 2 functions but in reality I've got many that all do the same thing.
import React, {useState} from "react"
const Section = ({ children }) => {
return (
<>
<Wrapper children = {children} />
</>
);
};
const HandlePages = () => {
const [showPageFooDialogue, setShowPageFooDialogue] = useState(false);
const [showPageBarDialogue, setShowPageBarDialogue] = useState(false);
const [currentDialogue, setCurrentDialogue] = useState(0);
{showPageFooDialogue && (
<Section>
<Headers heading = {"Foo Title"} currentDialogue = {currentDialogue} pages = {fooContents.length} />
{fooContents[currentDialogue]}
</Section>
)}
)
{showPageBarDialogue && (
<Section>
<Headers heading = {"Bar Title"} currentDialogue = {currentDialogue} pages = {barContents.length} />
{barContents[currentDialogue]}
</Section>
)}
)
}
const fooContents = [
//Lots of functionality specific to foo listed as the children of this function
];
const barContents = [
//Lots of functionality specific to bar listed as the children of this function
];
return (
<button onClick={() => setShowPageFooDialogue(true)}>Click for Page Foo</button>
<button onClick={() => setShowPageBarDialogue(true)}>Click for Page Bar</button>
)
}
export default HandlePages
Basically where I've got
const [showPageFooDialogue, setShowPageFooDialogue] = useState(false);
const [showPageBarDialogue, setShowPageBarDialogue] = useState(false);
I need just one function such as this but somehow pass 2 parameters to it:
const [showPageGenericDialogue, setShowPageGenericDialogue] = useState(false);
and where I've got:
{showPageFooDialogue && (
<Section>
<Headers heading = {"Foo Title"} currentDialogue = {currentDialogue} pages = {fooContents.length} />
{fooContents[currentDialogue]}
</Section>
)}
)
{showPageBarDialogue && (
<Section>
<Headers heading = {"Bar Title"} currentDialogue = {currentDialogue} pages = {fooContents.length} />
{barContents[currentDialogue]}
</Section>
)}
)
}
I need just one function with 2 parameters for "Foo or Bar Title" (param1) and fooContents or barContents (param2):
{showPageGenericDialogue && (
<Section>
<Headers heading = {param1} currentDialogue = {currentDialogue} pages = {param2.length} />
{param2[currentDialogue]}
</Section>
)}
)
}
And then finally the buttons:
<button onClick={() => setShowPageFooDialogue(true)}>Click for Page Foo</button>
<button onClick={() => setShowPageBarDialogue(true)}>Click for Page Bar</button>
should just pass the parameters something like:
<button onClick={() => setShowPageGenericDialogue(true, fooParam1, fooParam2)}>Click for Page Foo</button>
<button onClick={() => setShowPageGenericDialogue(true, barParam1, barParam2)}>Click for Page Bar</button>
I've looked at various solutions but due to my limitations, I cannot apply them to this.
Any ideas?
Thanks.
You can use reducer:
https://reactjs.org/docs/hooks-reference.html#usereducer
It is a simple example, you can modify as per your needs.
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
Or Take a look at react-redux.
EDIT
If you need functionality like you asked one function with multiple parameter
you can try to give a default state to your useState hook:
const [myFooBar, setFoo] = useState(
{
'foo': false,
'bar': false
}
);
Changing the values:
setFoo(
prevState => ({
...prevState,
'foo': true
})
);
setFoo(
prevState => ({
...prevState,
'bar': true
})
);
Access it like this:
myFooBar.foo
myFooBar.bar
Hi i am working on a React application where there are four options.when a user select an option corresponding input element will be added to the wrapper.In the following code add operation works fine but remove operation is not working properly ,it is not removing the corresponding element.Another problem the values on the inputs fields not present when the component re-renders.so experts guide me how i can acheive removing the corresponding row when the remove button is clicked and the input values should not be reset when the component re-renders.
But when I submit the input it will appear my data perfectly and when i restart the page and just click into edit and hit submit with the defaultValue it just clear all the data and send back to my backend with undefined value like this: [ undefined, undefined, undefined, undefined ]
Here is my full component:
const Agreement = (props) => {
const { agreement, editable, teamData, teamId, fetchTeamData } = props;
const [editing, setEditing] = useState(false);
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [showErrors, setShowErrors] = useState(false);
const [errorsArr, setErrorsArr] = useState();
const initialFormState = {
rule_0: teamData.rules.rule_0,
rule_1: teamData.rules.rule_1,
rule_2: teamData.rules.rule_2,
rule_3: teamData.rules.rule_3,
creator: teamData.User.public_user_id,
};
const [updateTeamData, setUpdateTeamData] = useState(initialFormState);
const [inputs, setInputs] = useState(teamData.rules);
const handleChange = (event) => {
const { name, value } = event.target;
// Update state
setUpdateTeamData((prevState) => ({
...prevState,
[name]: value,
}));
};
// Add more input
const addInputs = () => {
setInputs([...inputs, { name: `rule_${inputs.length + 1}` }]);
};
// handle click event of the Remove button
const removeInputs = (index) => {
const list = [...inputs];
list.splice(index, 1);
setInputs(list);
};
const clearInput = (dataName) => {
setUpdateTeamData((prevState) => {
delete prevState[dataName];
return {
...prevState,
};
});
};
const handleSubmit = async (event) => {
event.preventDefault();
setEditing(false);
// Send update request
const res = await axios.put(`/api/v1/teams/team/${teamId}`, updateTeamData);
// If no validation errors were found
// Validation errors don't throw errors, it returns an array to display.
if (res.data.validationErrors === undefined) {
// Clear any errors
setErrorsArr([]);
// Hide the errors component
setShowErrors(false);
// Call update profiles on parent
fetchTeamData();
} else {
// Set errors
setErrorsArr(res.data.validationErrors.errors);
// Show the errors component
setShowErrors(true);
}
};
const handleCancel = () => {
setEditing(false);
};
useEffect(() => {
if (agreement === "default") {
setTitle(defaultTitle);
setInputs(teamData.rules);
} else {
setTitle(agreement.title ?? "");
}
}, [agreement, teamData]);
console.log("teamData.rules", teamData.rules);
console.log("inputs", inputs);
return (
<div className="team-agreement-container">
{!editing && (
<>
<h4 className="team-agreement-rules-title">{title}</h4>
{editable && (
<div className="team-agreement-rules">
<EditOutlined
className="team-agreement-rules-edit-icon"
onClick={() => setEditing(true)}
/>
</div>
)}
<p className="team-agreement-rules-description">{description}</p>
{teamData.rules.map((rule, index) => (
<div className="team-agreement-rule-item" key={`rule-${index}`}>
{rule ? (
<div>
<h4 className="team-agreement-rule-item-title">
{`Rule #${index + 1}`}
</h4>
<p className="team-agreement-rule-item-description">
- {rule}
</p>
</div>
) : (
""
)}
</div>
))}
</>
)}
{/* Edit rules form */}
{editing && (
<div className="team-agreement-form">
{showErrors && <ModalErrorHandler errorsArr={errorsArr} />}
<h1>Rules</h1>
{inputs.map((data, idx) => {
return (
<div className="agreement-form-grid" key={`${data}-${idx}`}>
<button
type="button"
className="agreement-remove-button"
onClick={() => {
removeInputs(idx);
clearInput(`rule_${idx}`);
}}
>
<Remove />
</button>
<input
name={`rule_${idx}`}
onChange={handleChange}
value={teamData.rules[idx]}
/>
</div>
);
})}
{inputs.length < 4 && (
<div className="team-agreement-add-rule">
<button type="submit" onClick={addInputs}>
<Add />
</button>
</div>
)}
<div className="div-button">
<button className="save-button" onClick={handleSubmit}>
Save
</button>
<button className="cancel-button" onClick={handleCancel}>
Cancel
</button>
</div>
</div>
)}
</div>
);
};
export default Agreement;
How can I fix this error?
My thought is the problem is around [inputs, setInputs]
Try this
<input
//..
onChange={(event) => handleChange(event.target.value)}
//..
/>
then in your "handleChange" function
const handleChange = (event) => {
const { name, value } = event;
//....
};
Parent Component:
const initialValue_modalProps = [
{ show: false, response: "" }
];
const [modalProps, setModalProps] = useState(initialValue_modalProps)
const passedFunction = () => {
setModalProps(modalProps => initialValue_modalProps);
}
..
..
<div>
<Modal show={modalProps.show}
response={modalProps.response}
passedFunction={passedFunction}></Modal>
</div>
Child Component:
export default function ModalComp(props) {
const [modalOpen, setmodalOpen] = useState(true);
console.log('modalOpen', modalOpen);
if (props.show === false || modalOpen === false) {
return null;
}
return (<Modal isOpen={props.show}>
<ModalHeader>Deployment Status</ModalHeader>
<ModalBody>{props.response}</ModalBody>
<ModalFooter>
<Button onClick={() => {
setmodalOpen(modalOpen => false);
props.passedFunction();
}}>Close</Button>
</ModalFooter>
</Modal>)
}
Here I want to passedFunction function from Parent to child so that the Child component can execute it to reset the state in parent
You can take this as an reference with live example demo https://codesandbox.io/s/modal-6fvyx
function App() {
const [status, setState] = React.useState(false);
const [text, setText] = React.useState("");
const handleClick = () => {
setState(prevStatus => !prevStatus);
};
const handleChange = e => {
setText(e.target.value);
};
return (
<>
<button onClick={handleClick}>Open photo entry dialog</button>
<ChildComponent
isOpen={status}
text={text}
handleChange={handleChange}
handleClick={handleClick}
/>
</>
);
}
const ChildComponent = ({ isOpen, text, handleChange, handleClick }) => {
return (
<>
{isOpen && (
<Model
status={isOpen}
handleClick={handleClick}
text={text}
handleChange={handleChange}
/>
)}
</>
);
};
You need to remove the parentheses behind passedFunction, because otherwise you are executing the function first and passing the result to the child afterwards. Pass your function as it is via passedFunction={passedFunction}.
const ParentComponent = () => {
const initialModalProps = { ... };
const [modalProps, setModalProps] = useState(initialModalProps);
const passedFunction = () => {
setModalProps(initialModalProps);
}
return (
<div>
<Modal
show={modalProps.show}
response={modalProps.response}
passedFunction={passedFunction} />
</div>
);
};
Changed the child component to this. and its working
export default function ModalComp(props) {
//const [modalOpen, setmodalOpen] = useState(true);
if (props.show === false) {
return null;
}
return (<Modal isOpen={props.show}>
<ModalHeader>Deployment Status</ModalHeader>
<ModalBody>{props.response}</ModalBody>
<ModalFooter>
<Button onClick={props.passedFunction}>Close</Button>
</ModalFooter>
</Modal>)