Proper way to set state between two react components - javascript

I have a component for a Navbar and a component for a Sidebar. The sidebar component has a state variable that decides whether or not it should be open. Here is what I have.
export default class Sidebar extends Component {
constructor() {
super(...arguments);
this.state = { open: false };
}
toggle() {
this.setState({ open: !this.state.open });
}
render() {
return (
<LeftNav open={this.state.open}>
<MenuItem
onClick={this.toggle.bind(this)}
primaryText="Close"
leftIcon={<CloseIcon/>}
/>
</LeftNav>
)
}
}
The problem I am having is in accessing the toggle functionality from a separate component, the Navbar.
<AppBar
title="Navbar"
iconElementLeft={
<IconButton onClick={}> // want to enable clicking here to close sidebar component
<MenuIcon>
</IconButton>
}
/>
What I am wondering is, what is the best practice to set the state of separate components?

You have entered into the exciting realm of "data flow".
One way to implement this is to have some sort of centralized object that listens for events and dispatches information to other components. In other words, your NavBar handler can dispatch what many frameworks refer to as an "action" with some information, and then other components can re-render based on the information from that event.
A library that's gaining some popularity is redux if you're into a pre-packaged solution for this kind of thing. If nothing else, it'll help you gain some insight into how other people are currently doing this type of thing.

Related

reactjs - show dialog on all pages using a button component, wherever it is included

In my react app, I have a header with a show dialog button.
This header component is included in all pages as necessary.
My current logic to show the dialog is as follows:
When user clicks the button, I dispatch an action to redux store { type:SHOW_DIALOG }, and let the parent component handle the state change and draw the dialog. I am using material-UI swipeable drawer component.
Handle Click event in an iconbutton in header component...
const handleClick = () => {
/*
* temporary bypass surgery to avoid going through login dialog
* dispatch({type:'SHOW_CONTACT_INFO'})
* return;
*/
if (!isLoggedIn) dispatch({type: 'SHOW_LOGIN_DLG'})
else router.push('/my-account')
}
In the parent page, where the header is contained...
// ...other code
<Container>
{/* Whether or not to show the login dialog . */}
{loginProcessState>=1 && loginProcessState<=7
?<LoginDialog type={loginProcessState===1?"login":"otp"} />
: null}
{/* if contact edit dialog is set to show, show it. */}
{contactEditDisplay? <ProfileEditDialog />:null}
</Container>
);
But, since I have many pages (around 10 pages and server side rendering with NextJS), I will have to repeat the state management in all those pages where the dialog must be shown.
Excuse my lack of knowledge here. Is it possible to avoid this dialog state check in the parent component / page. If so, how can i do it?
Suggestion:
Move the LoginDialog component up and render it directly within the root <App/> component.
And then use React.useContext to call that dispatch in various components to trigger loginProcessState.
The above should help you render the Login acros all components.

In React how to stop rendering components which state or props not changed?

I got an issue in my project , that I had a main component which acts as the parent component of my project inside that I had the routes for the other components and some other component which are directly imported into it like a Side Navbar Component and Login Component so which are triggered on an event button click , but when I open those components all the other components are re-rendering .
export const AppFramework = (props) => {
const [isOpen, setIsOpen] = useState(false);
const [isSideNav, setIsSideNav] = useState(false);
const OptimizedRoutes = React.memo(AppRoutes);
useEffect(() => {
console.log('AppFramework Mounted');
}, []);
// Methods For Opening and closing of Login and SideNav
const handleOpen = useCallback(() => {
setIsOpen(true);
}, [isOpen]);
const handleClose = useCallback(() => {
setIsOpen(false);
}, [isOpen]);
const openSideNav = useCallback(() => {
return setIsSideNav(true);
}, [isSideNav]);
const LoginPopBody = (
<div className="pop-window">
<Button startIcon={<Close />} onClick={handleClose}></Button>
{/* {For Fields for loggin in .........} */}
</div>
);
return (
<Router>
<HideOnScroll>
<AppBar color="default" className="app-header">
<Button startIcon={<Menu />} onClick={openSideNav}></Button> // Button To Open Side Navbar
<Button onClick={handleOpen}>Login</Button> /* Button To Open Login Popup */
</AppBar>
</HideOnScroll>
//sidenav comp passing props to open and close below
<SideNav open={isSideNav} close={setIsSideNav} />
//routes are below
<main className="main-blk">
<Suspense fallback={<div>Loading...</div>}>
<OptimizedRoutes />
</Suspense>
</main>
<Modal open={handleOpen}>{LoginPopBody} </Modal>
</Router>
);
};
export default React.memo(AppFramework);
On opening and closing of both login popup and side navbar renders every component .I tried React.memo in each component but nothing happened , I hope hooks will give a solution for this.
And one more thing while entering each input on login popup form fields also renders every components behind the login popup . what will be the solution for these issues ?
This might not be the answer you are satisfied with but most of the time these problems pop up because of the way you design/construct your components. In react planning the components is the first and in my opinion the most important thing. It can save us from a lot of trouble. In this case You need to keep the components linked but independent of each other.
I would recommend you to read https://reactjs.org/docs/thinking-in-react.html. This might help you.
Changing the state will definitely re-render the whole component. But to avoid some components to stop re-rendering or re-render on come custom state changes you can use useCallBack hook.
The following article might help.
https://kentcdodds.com/blog/usememo-and-usecallback/
You can put the other component in individual functions and use useCallback hook on those function. This way you can define on which state change should those functions be used again.
Actually the issue is resolved , actually my problem is very simple , its not a complicated problem , To open the Side Navbar and Login Component I don't need to pass a boolean value from the parent component as a Prop .
Instead of that, we can get the boolean value from the own component by a passing a boolean value to the module to be shown in my case I used Material UI's Modal and Drawer by an event like button click or any other event .
This is what I did to solve my issue . In short I made the components independent.

Send event to another class

in my web react project i have two class one "Menu" return the Menu for my dashboard (the links to change the pages "Home" , "messages" ....) and another one "Box" for show the pages (it's the container of my website pages ) so my question is how the page when i click button ?.
class menu(){
render(){
return(<button>click to go to home</button>) ;
}
}
class box(){
render (){
return(<Home>this is the home</Home>) ;
} }
You can create a parent component that has the page property and the setPage method.
Inside that component, render the toolbar and the pages. The toolbar should accept a prop that'll called onClickPage that should dispatch the setPage. For example:
const [page, setPage] = React.useState("dashboard");
....
<Toolbar onClickPage={page => setPage(page)} />
<Pages page={page} />
This is what's called Lifting the state up (https://reactjs.org/docs/lifting-state-up.html) I suggest you to read their docs. It's very beginners friendly.
If your main problem is to navigate between pages you can easily achieve this by using react-router.
https://reactrouter.com

how to re-render React component each and every time freshly with animation

Hi I have a Single Page Application,
when we load the page I am creating some animation. If user is in same page and reload this component that animation is not happening. I believe that , since the DOM is not updated without state or props, I think that animation is not happening again.
For reloading , consider that component is coming from back-end.
I am allowed to use state.
I just fiddle the code here. Please consider this component is coming from backend every time.
I tried with this.forceupdate, inside componentDidUpdate -- It didn't work
and then I added state in parent div with Date.now() like below
constructor(props)
{
constructor(props)
this.state={
time:Date.now()
}
}
<div data-value={this.state.time}>
Not worked.
I created fiddle for testing. My component is same like in the fiddle. I want to do animation every time the page loads (If above part is not understandable please consider clicking on same URL and load this component with animation on each click )
https://jsfiddle.net/nye3jcz8/
This is somewhat of a hack solution and is not necessarily great from a performance perspective, but you could assign a random key prop to the component. This would essentially cause React to treat it as a new component each time and mount a new replica component in its place which should animate.
Your animation is playing on mount, which is why nothing related to state is working. On a state change, the component updates rather than remounts. The fix above is designed to force an unmount/remount.
That said, you should probably write a function that allows you to trigger this animation at will rather than through lifecycle-manipulation weirdness. You could do this by adding behavior to remove or apply a CSS class, which would allow you to achieve the desired effect and would likely be better from a predictability perspective.
For a component to re-render the best way is to use the key prop. Whenever the key prop changes, the component unmounts and re-mounts. I see that this is what you are looking for.
I created a small example from your code.
Check it out:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
componentDidMount() {
setInterval(() => {
this.setState({ count: this.state.count + 1 });
}, 1000);
}
render() {
return (
<div key={this.state.count}>
<div className="drawLine">I am drawing the at top</div>
</div>
);
}
}
You can do it your own way, depending on your application.

Trouble making stateful React components work together

I'm making a React App and i'm struggling to get the basic functionality of components with state working. So far i've got a home page that connects to a registration page, when I click to the registration page I can handle user input. The registration is the class component I am trying to use state in so far.
I've set up a pretty basic process so far in this component just to see if it works. But when I click the button to console log what is currently stored the entire page reloads as if nothing has happened.
A very basic display of what it currently looks like:
import registerUser from './user.js';
class App extends Component {
render() {
return (
<Router>
<Route path='/register' component={registerUser}/>
</Router>
)
}
}
export default App;
class registerUser extends Component {
handleChange = () => {
console.log('test');
}
render() {
return (
<div>
<button onClick={this.handleChange}>Click</button>
</div>
)
}
export default registerUser;
But as I mentioned when I click the button the entire page just reloads as if nothing has occured. Am I missing something something basic as to why trying to use this method in a separate component reloads the entire app?
Any help would be greatly appreciated.
If the button is inside a form, then you must write e.preventDefault() in your handleChange function,
handleChange = (e) => {
e.preventDefault(); //It will prevent form submit
console.log('test');
}
Demo
Note: React component name should be in PascalCase, so just replace registerUser to RegisterUser.

Categories

Resources