Am trying to render a new component onclick a button in react js. Am using functional components and I can't handle it. Eg: am in the UserManagement component and on a button click I need to render another component named employee management.
You can conditionally render your component.
Example :
EmployeeManagement.js
const EmployeeManagement = () => {
....
return (
<div>
EmployeeManagement
</div>
);
}
UserManagement.js
const UserManagement = () => {
const [hasRender, setRender] = useState(false);
const onShow = React.useCallback(() => setRender(true), []);
return (
<>
<button onClick={onShow}>Show Employee Management</button>
{hasRender && <EmployeeManagement />}
</>
)
}
One way to do this would be to add a local state in UserManagement,
that holds a boolean value indication whether the component should be hidden or shown.
Then you will have something like:
function UserManagement() {
const [compIsShown, setCompIsShown] = useState(false);
return (
// Whatever else you're rendering.
<button onClick={() => setCompIsShown(true)}>...</button>
{compIsShown && <OtherComp />}
)
}
What will happen is that compIsShown will initialize as false,
so this condition compIsShown && <OtherComp /> will prevent it from rendering.
Then, when you click the button, the state will set, causing a re-render, except now the condition will be true, so <OtherComp> will be rendered.
There are other ways to go about this.
Depends mostly on the use-case.
use a visible state & toggle it in onClick:
const [visible, setVisible] = useState(false)
onClick = () => {setVisible(true)}
then render it like this:
{visible && <EmployeeManagement onClick={onClick} />}
Related
I have a parent component with a handler function:
const folderRef = useRef();
const handleCollapseAllFolders = () => {
folderRef.current.handleCloseAllFolders();
};
In the parent, I'm rendering multiple items (folders):
{folders &&
folders.map(folder => (
<CollapsableFolderListItem
key={folder.id}
name={folder.name}
content={folder.content}
id={folder.id}
ref={folderRef}
/>
))}
In the child component I'm using the useImperativeHandle hook to be able to access the child function in the parent:
const [isFolderOpen, setIsFolderOpen] = useState(false);
// Collapse all
useImperativeHandle(ref, () => ({
handleCloseAllFolders: () => setIsFolderOpen(false),
}));
The problem is, when clicking the button in the parent, it only collapses the last opened folder and not all of them.
Clicking this:
<IconButton
onClick={handleCollapseAllFolders}
>
<UnfoldLessIcon />
</IconButton>
Only collapses the last opened folder.
When clicking the button, I want to set the state of ALL opened folders to false not just the last opened one.
Any way to solve this problem?
You could create a "multi-ref" - ref object that stores an array of every rendered Folder component. Then, just iterate over every element and call the closing function.
export default function App() {
const ref = useRef([]);
const content = data.map(({ id }, idx) => (
<Folder key={id} ref={(el) => (ref.current[idx] = el)} />
));
return (
<div className="App">
<button
onClick={() => {
ref.current.forEach((el) => el.handleClose());
}}
>
Close all
</button>
{content}
</div>
);
}
Codesandbox: https://codesandbox.io/s/magical-cray-9ylred?file=/src/App.js
For each map you generate new object, they do not seem to share state. Try using context
You are only updating the state in one child component. You need to lift up the state.
Additionally, using the useImperativeHandle hook is a bit unnecessary here. Instead, you can simply pass a handler function to the child component.
In the parent:
const [isAllOpen, setAllOpen] = useState(false);
return (
// ...
{folders &&
folders.map(folder => (
<CollapsableFolderListItem
key={folder.id}
isOpen={isAllOpen}
toggleAll={setAllOpen(!isAllOpen)}
// ...
/>
))}
)
In the child component:
const Child = ({ isOpen, toggleAll }) => {
const [isFolderOpen, setIsFolderOpen] = useState(false);
useEffect(() => {
setIsFolderOpen(isOpen);
}, [isOpen]);
return (
// ...
<IconButton
onClick={toggleAll}
>
<UnfoldLessIcon />
</IconButton>
)
}
I have this
function Toggle(){
const [toggleOn, setToggleOn] = useState(false);
return (
<div>
{toggleOn == true && <Settingson className={classes.settingson} onClick={() => setToggleOn(d => !d)} value="true" name="toggle"/>}
{toggleOn == false && <Settingsoff className={classes.settingsoff} onClick={() => setToggleOn(d => !d)} value="false" name="toggle"/>}
</div>
)
}
export default Toggle;
And somehow I want to get the value of this
<Toggle />
I tried many things, but couldn't came up with a solution. Please help! I am new to React Next Js.
I tried to get the value of a jsx component, but It doesn't work. Somehow I need to check if the value of the toggle is true or not.
Your component needs to be authored so that it can inform its consuming component that its state has changed: see it as a way data is "emitted" from a child component.
In the example below, I have updated your component so that it accepts a onInput prop, which should be a method. It is invoked whenever the click event is fired, and "piggy-backs" on the state change to toggleOn:
function Toggle({ onInput }){
const [toggleOn, setToggleOn] = useState(false);
const onToggleClick = (value) => {
// Updates internal state
setToggleOn(value);
// Fires the callback passed as a prop
onInput(value);
};
return (
<div>
{toggleOn == true && <Settingson className={classes.settingson} onClick={() => onToggleClick(d => !d)} value="true" name="toggle"/>}
{toggleOn == false && <Settingsoff className={classes.settingsoff} onClick={() => onToggleClick(d => !d)} value="false" name="toggle"/>}
</div>
)
}
export default Toggle;
Then in the parent component it is a matter of passing in a function to the prop, e.g.:
const onToggleInput = (value) => console.log(value);
return <Toggle onInput={onToggleInput} />
Not sure if I get what you are trying to do but I think you can simplify in a similar way
function Toggle(){
const [toggleOn, setToggleOn] = React.useState(false);
const handleToggle = () => {
console.log("toggleOn",toggleOn)
setToggleOn(prev => !prev)
}
return (
<div>
<button onClick={handleToggle} value={toggleOn} name="toggle">something</button>
</div>
)
}
just replace the button with your component Settings, you just need one that handles true/false values or add a conditional ternary operator for conditional rendering.
return toggleOn ? <TrueComponent /> : <FalseComponent />
I'm a bit surprised I'm having trouble finding this online, but I can't seem to find an example of how to do this in a React functional component. I have a React component that I would like to render when I click a button. Right now the function fires and I can see my console.log firing, however the component isn't rendering. My first guess was that it won't render because React doesn't know to update the view, however I added boolean via useState and it still won't render. What am I doing wrong?
Below is the relevant code. How can I get the component in addSection to render?
const FormGroup = ({index}) => {
const [additionalSection, setAdditionalSection] = useState(false);
const addSection = form => {
setAdditionalSection(true);
console.log('form', form);
return additionalSection && (
<div key={form.prop}>
<p>This should render</p>
<AdditiveSection
form={form}
register={register}
errors={errors}
/>
</div>
);
};
...
return (
...
<FormAdd>
<LinkButton
type="button"
onClick={() => addSection(form)}
>
span className="button--small">{form.button}</span>
</LinkButton>
</FormAdd>
);
You should change your state (or a prop in your useEffect dependency array in case you had one) in order to force a rerender. In this case:
setAdditionalSection(prevState=>!prevState);
A state change like the one you are calling, will trigger a re-render.
But all html to be rendered must be included in the functional components return statement.
The elements you want to render can be conditionally rendered like this:
const FormGroup = ({index}) => {
const [additionalSection, setAdditionalSection] = useState(false);
const addSection = form => {
setAdditionalSection(true);
console.log('form', form);
};
...
return (
...
<FormAdd>
<LinkButton
type="button"
onClick={() => addSection(form)}
>
<span className="button--small">{form.button}</span>
</LinkButton>
{additionalSection &&
<div key={form.prop}>
<p>This should render</p>
<AdditiveSection
form={form}
register={register}
errors={errors}
/>
</div>
}
</FormAdd>
);
So basically I want when I press on the Button I want to Icon to disappear as well as Button. I have tried something but clearly, it is not working, so I would appreciate some help if possible
const Button = (props) => {
const[toggleIcon, setToggleIcon]=React.useState('true')
function Icon() {
toggleIcon(false)
}
return(
<div>
<button onClick={()=> setToggleIcon('false')}></button>
</div>
)
}
export default Button
const Icon = (props) => {
return(
<div>
<Icon>{props.Icon('false')}</Icon>
</div>
export default Icon
You can prevent a component from rendering by returning null. Use conditional rendering with the toggleIcon state as the condition. The onClick handler changes the state.
E.G.:
const Button = () => {
const [toggleIcon, setToggleIcon] = React.useState(true)
return toggleIcon ? (
<button onClick={() => setToggleIcon(false)}><Icon /></button>
) : null
}
export default Button
Take a look at the Conditional Rendering section of the React docs.
How can I check if an element is present in the DOM or not, using React?
I have a popup that is displayed throughout the application when items are 0 and the user clicks a button. It's created by a context provider that is wrapped around the App component.
There is an add button that gets displayed in some page "/items".
const root = () => {
<PopupContextProvider>
<App/>
</PopupContextProvider>
}
export const PopupContextProvider = ({ children }: any) => {
return (
<popupContext.Provider value={context}>
{children}
{(condition1 || condition2) && (
<Popup onHide={dismiss} />
)}
</popupContext.Provider>
);
}
function App() {
return (
<Route path="/items">
<Drawer/>
/>
//other routes
);
}
function Drawer() {
return (
<ButtonElement/> //this is a styled div component and i want to check if this element is
//present in dom at the sametime when popup is there in dom
);
}
What I want to do?
I want to check if the ButtonElement is there in the DOM at the same time as the popup.
The ways that I have thought:
add an id to button element and check if it is present using document.getelementbyid (last option for me)
using ref, but I'm not sure how to do it
I want to use a ref to button element, but I don't know how to pass it to context.
What would be the best way to do this?
Use the useRef hook and pass it down to the child component. It'll be undefined
Assuming you're defining const popupContext = React.createContext(undefined); somewhere, roughly this should work:
const PopupContextProvider = ({ children }: any) => {
const popupRef = useRef(null);
return (
<popupContext.Provider value={popupRef}>
{children}
{(condition1 || condition2) && (
<Popup onHide={dismiss} ref={popupRef}/>
)}
</popupContext.Provider>
);
}
const Drawer = () => {
return (
<popupContext.Consumer>
{value => (value !== undefined)
? <ButtonElement popup={true}/>
: <ButtonElement/>
}
</popupContext.Consumer>
);
}
More info about context usage here: https://reactjs.org/docs/context.html#reactcreatecontext