How to re render a static component in reactjs - reactjs

I am developing a webapp in reactjs using typescrpit in visual studio 2017, which is very new technology for me. I am stuck at a problem where i dont know how to re-render a component from another component.
I have a log in page. What i want to do is display the username in my header component when the user logs in. Only problem is, the header component is common for all my web pages. Following is my layout.tsx file:-
export interface LayoutProps {
children?: React.ReactNode;
}
export class Layout extends React.Component<LayoutProps, {}> {
public render() {
return <div>
<Header />
<div className='layout_wrapper'>
{this.props.children}
</div>
<Footer />
</div>;
}
}
This is the only file where i have used my header component so that i wont have to use it in every component i create. componentDidMount() of header component will check for access token and make an api call to get user details. Now my question is, how can i re-render this component from another component so that when the user logs in, he can see his name in this header component? Please tell me if i need to provide more code if my question is not clear. Thanks

Considering this is a small app, this solution will work. But it shouldn't be used when the app isn't a small one, because it will make the code complex.
So, according to information given by you, the hierarchy is as follows:
<Header>
<SignIn>
<SignInContent/>
</SignIn>
</Header>
,where SignInContent component is calling the api. We will define a function in Header, and pass it as props to the SignIn component
export class Header extends React.Component<HeaderProps, HeaderState> {
constructor(){
this.state = { isLoggedIn: false }; //Add this to existing state variables
}
render() {
return {
<SignIn setIsLoggedInTrue={this.setIsLoggedInTrue.bind(this)} />
}
}
componentDidUpdate(prevProps, prevState) {
if(this.state.isLoggedIn && !prevState.isLoggedIn) {
// Make the api call for fetching user details
}
}
setIsLoggedInTrue() {
this.setState({isLoggedIn: true});
}
}
And in the SignIn component, again in the render method pass the props to SignInContent like this:
<SignInContent setIsLoggedInTrue={this.props.setIsLoggedInTrue} />
once it is logged in, you can call this.props.setIsLoggedInTrue function from the SignInContent component. This should solve your purpose

Your component will be re-rendered if the supplied props have changed.
By looking at your code, the value of this.props.children should change which will eventually trigger a re-render of your component
Also, if you want to know how to trigger it at login. There should be a componentWillReceiveProps method which checks the login state of the user, and if found logged in will update the values passed to the component :)
EDIT
Here's a sample code to your problem. Since this.props.children is used. You'll need to use it like this.
render() { return (
<Layout>
{this.state.userName}
</Layout>
);}
Now call the api and set the userName

Related

How to render component depends role

so I have a specific code.
The problem is it's not works in moments - when it's should.
I need refresh page to works.
If user from LocalStorage is null it's should render
If user from LocalStorage exist it's shouldn't render
It's works, but how can I improve it to works after login (not after refreshing page) ?
Should I use other react lifecycle method?
class Navbar extends React.Component {
constructor(props){
super(props)
this.state ={
user: null
}
}
componentDidMount(){
const user = JSON.parse(localStorage.getItem('user'));
this.setState({
user: user
},
console.log('test'+ this.state.user)
)
}
render(){
return(
<div>
{ !this.state.user ?
<div className ="navbar">
<Logo/>
<Menu/>
<PanelOptions/>
</div>
: null}
</div>
);
}
}
Looking at the component it seems that it can be a functional component.
And the user can be sent as a prop from parent component which is rendering the NavBar component.
export default NavBar = (props) => {
if(!props.user)
{
return (
<div className ="navbar">
<Logo/>
<Menu/>
<PanelOptions/>
</div>
)
}
else
{
return null
}
}
Should I use other react lifecycle method?
No, it won't help. Local storage change is not observed, can't be a reason of rerendering.
What is the reason of storing user data in local storage? Sharing data between components shouldn't be the [primary] one.
Components are rerendered on props or state changes. You can pass some value (f.e. isLogged or simply user) from parent state (where probably the login process is handled). If login is processed in sibling child that you need lifting state up - one of basic react techniques.

How to change state of component from anywhere without Redux?

Is this bad practices or not ?
export state change function from component
import it from other file.
call the function to change state?
In this way we can change some component state from anywhere.
For example...
We want to change the Model.js state from anywhere.
Modal.js
import React from 'react';
export let toggleModal;
export default class Modal extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
};
toggleModal = this.toggleModal;
}
toggleModal = () => {
this.setState({ open: !this.state.open });
};
render() {
const { open } = this.state;
return <div style={{ color: 'red' }}>{open && 'Hello Modal'}</div>;
}
}
App.js(Some Top Level component)
import React from 'react';
import Modal from './Modal';
export default () => (
<>
...
<Modal />
...
</>
);
Somewhere.js
import React from 'react';
import {toggleModal} from './Modal';
export default () => (
<>
<h1>Hello!</h1>
<button onClick={() => toggleModal()}>open Modal!</button>
</>
);
  
But there is no reference in React Official docs, so is this bad practices ?
What React Docs recommends...
Just passing function props to change parent state from parent to children
Use context
Redux or Mobx
But, these are too complex for me.
Example code here
https://next.plnkr.co/edit/37nutSDTWp8GGv2r?preview
Everything seems pretty much overwhelming and difficult at the beginning. But as we get out hands on them, it's give us more confidence to dig into.
I would recommend to use redux that's how we tackled props drilling problem. You can dispatch a action and connect reducer to corresponding component which upon updating state will re render. This is what I recommend to most of the people to learn the tale of redux with a real life example:
Understanding Redux: The World’s Easiest Guide to Beginning Redux
Apart from this you can take Dan Abramov, author of the library, free redux course on egghead.io:
Getting Started with Redux
The problem you run into, almost immediately like your code example does is this:
It will not work: your toggleModal() method expects a this to refer to an actual component instance. When your onClick() handler fires you invoke toggleModal() as a plain function. The this context will be wrong, and so at best (in your example) you will get an error because you try to invoke something undefined, at worst (in general) you end up invoking the wrong method.
When you think about it, for any non-trivial React component you will have a hard time obtaining a reference to the actual instance that is currently being used: you have to make sure that you are not forgetting to invoke the method on the right component instance and also you have to consider that instances may be created/destroyed 'at will' for whatever reason. For example: what if your component is rendered indirectly as part of some other component's render() method? Multiple layers of indirection like that make it even harder.
Now, you could fix all that by abusing ref with abandon but you will find that now you have to keep track of which ref refers to what particular instance, if you happen to have multiple of the components to consider in one render tree...
Whenever you think one component needs to handle the state of its siblings, the solution is usually to lift the state one level up.
export default class Modal extends React.Component {
render() {
const { isOpen } = this.props;
return <div style={{ color: 'red' }}>{isOpen && 'Hello Modal'}</div>;
}
}
export default class Home {
this.state = {
isOpen: false,
};
toggleModal = () => {
this.setState({ isOpen: !this.state.isOpen });
}
render() {
const { isOpen } = this.state;
return (
<>
<h1>Hello {name}!</h1>
<button onClick={() => this.toggleModal()}>open Modal!</button>
<Modal isOpen={isOpen}/>
<p>Start editing and see your changes reflected here immediately!</p>
</>
)
}
}
This way the Home handle the state and your problem is solved.
This can get annoying if the state needs to be "drilled down" to children, that's a problem than redux or react-context can solve.
Here <Modal /> is the child component. So to call a function in a child component you can simply use Ref.
You can refer this page to get more info about Ref.
You can assign a class variable as a ref to this child and use this class variable as an object to call its function.
I found if in special case, my way is okay.
Special case means something like customAlert component.
It is okay only one instance of customAlert component mounted at a time in App.
To achieve this...
1.Use ref to access and change DOM
2.attach state changing function or component to window and call window.function
3.my case: export state changing function and import it from other file.
And here is how to do with react Context
https://next.plnkr.co/edit/EpLm1Bq3ASiWECoE?preview
I think Redux is overkill if the main thing you are interested in is to make some states-like data available and updatable throughout your App without props drilling.
For that purpose, a much simpler approach (maybe not available at the time the question was posted?) is to use react context: https://frontend.turing.edu/lessons/module-3/advanced-react-hooks.html
"context - an API given to us by React, allowing for the passing of
information to child components without the use of props
[...]
useContext - a react hook, allowing functional components to take
advantage of the context API"

Update property in a component from parent-child component

In the root of my Application I have a Header component that contains an image. The root also contains a Page component which holds different content based on the Route.
The Header component has a property named HeaderImage (url) and I'd like to be able to update the HeaderImage (url) from the Page component.
Can anyone suggest a good approach, I was thinking of just adding some logic to the Header component that switched the HeaderImage (url) based on the Route but I'd like a little more flexibility. I'd ideally like to be able to update the image from the Page component children.
You can Pass the url to root and let root update it for Header using props like :
class Root extends React.Component {
render() {
constructor(props){
super(props);
this.state={
urlForHeader : null
}
this.updateUrl = this.updateUrl.bind(this);
}
function updateUrl(url){
this.setState({
urlForHeader : url
})
}
return (
<div>
<Header
url={this.state.urlForHeader}
/>
<PageContent
updatingFunction={this.updateUrl}
/>
</div>
);
}
}
Maybe what you need is to implement componentWillUpdate in your component, see this docs about it.
React js ComponentWillUpdate

Child component changing parent component state

Here there is app root component passing a handleHeaderTitle function to all its children by cloning.
Inside children components, the function is called in componentWillMount()
and as a result root component updates header text based on route.
Root :
{
this.props.children &&
React.cloneElement(this.props.children, {
handleHeaderTitle: this.handleHeaderTitle
})
}
handleHeaderTitle(title) {
this.setState({ headerTitle: title });
}
Child:
componentWillMount() {
this.props.handleHeaderTitle("Profile");
}
Profile.propTypes = { handleHeaderTitle: React.PropTypes.func };
Is this right usecase for adding redux since the state is not really local here as is being set from a child component on its parent ?
I think I will need to create actions like SET_PROFILE_HEADER and inside reducers, combine these. But still figuring out how to inform container root component that child component has changed the header title
To answer your question directly, you don't need Redux to solve your problem. Redux helps you when you have to maintain a lot of state, or when your state needs to be reflected parts of the application that don't have a close common ancestor. In other words, when it gets too cumbersome to use good old fashioned React state.
A more common approach to your specific problem in React would be to include your layout in the child component instead of the root. This avoids the issue of trying to get the child to control content in the parent. It helps preserve the "unidirectional data flow" which is what React is all about.
class Page extends React.Component {
render() {
return (
<div>
<div className='profile-header'>
{ this.props.headerTitle }
</div>
<div className='profile-content'>
{ this.props.children }
</div>
</div>
)
}
}
class MyFirstPage extends React.Component {
render() {
return (
<Page headerTitle='Header Title 1'>
<div>My content here</div>
</Page>
)
}
}

How can I find all nested Components using React/Redux?

I am looking to validate a form with Redux. I am trying to use make a form component which will iterate through children and find various input components (not to be confused with a native <input>.
I know there are a lot of open source solutions, but I'd like to understand some mechanics before jumping into picking any. I have a Form component setup to test like this:
import React from 'react';
export default class Component extends React.Component {
componentDidMount() {
this._iterate(this.props.children);
}
render(){
return (
<form {...this.props}>{this.props.children}</form>
);
}
_iterate(children) {
React.Children.forEach(children, child => {
console.log(child);
if (child.props.children) {
console.log('get children');
this._iterate(child.props.children);
}
});
}
};
I then have another Component with a render like this:
render() {
return (
<div>
<Form>
<ComponentA />
<ComponentB />
</Form>
</div>
);
}
Now ComponentA or ComponentB might have a component that nests more components down the line. Within those components would be a React component I have made for Text, Select, etc.
The code above would just console.log the components, and any children of them, that are in this specific render. It does not jump down into ComponentA children.
Is there a solution to that?
This isn't a problem you really want to solve.
The power in react is largely around the design pattern it encourages, and what you're doing is breaking that pattern; Component's should only talk to their immediate children and respond to their immediate parents. If you need to go deeper than that, then the component in the middle needs to be responsible for passing that data.
Rather than trying to dig into the innards of ComponentA and ComponentB, those component's themselves should have the accessibility props that you need. I.e., <ComponentA onChange={whatever} errorMessage={whatever}/> etc. and then hooking those props to their children should occur within ComponentA.

Resources