How to render component depends role - reactjs

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.

Related

What is state in React?

I know that state allows us to create components that are dynamic and interactive but I want to deep in state.
Can someone help me to understand state in React using a real life example?
import React from 'react';
class App extends React.Component {
state = {
count: 0
};
render() {
return (
<div>
<h1>Hello world</h1>
<h2>Count: {this.state.count}</h2>
<button
onClick={() => this.setState(state => ({ count: state.count + 1 }))}
>
+
</button>
<button
onClick={() => this.setState(state => ({ count: state.count - 1 }))}
>
-
</button>
</div>
);
}
}
export default App;
In the above code, it has a state object with property/state: count.
State can simply be understand as a value at that point of time of the particular component/app. In the above example, when the app is first running, the app is with state count === 0
As we can see there are two buttons + and - that update the value using this.setState, it simply update the "state" of count for the app, and the app will re-render, whenever the state change
For example:
import React, { Component } from "react";
import ReactDOM from "react-dom";
class App extends Component {
state = {
show: false,
}
showTextToggle = () => {
this.setState({ show: !this.state.show });
}
render() {
const { show } = this.state;
return (
<div>
<h3>Some title</h3>
{show ? <div>Description</div> : undefined}
<button onClick={this.showTextToggle}>Read more</button>
</div>
)
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
P.S. CodeSandBox
State in real life example:
Before someone upvoted your question, you can imagine your question or think it as question component had vote state = 0 and after that it became 1 and so on. So interactivity with the application changed something in the application. That changed something/ value can be called state.
State in application/ component can change due to interactivity(event) or during time.
As time you can imagine this Post or Post Component before 30 minutes/ some time ago had no answer i.e answer state = 0. And now it has some (3) answers. So answer state = 0 changed to answer state = 3.
State is just a value that a component/app is in at particular time.
Just imagine the specific point of time when you posted this question and now see the changes in this post. This changes can be thought as change in the state of the component/ app.
The state is an instance of React Component Class can be defined as an object of a set of observable properties that control the behaviour of the component. In other words, the State of a component is an object that holds some information that may change over the lifetime of the component. For example, let us think of the clock that we created in this article, we were calling the render() method every second explicitly, but React provides a better way to achieve the same result and that is by using State, storing the value of time as a member of the component’s state. We will look into this more elaborately later in the article.
State allows you to create components that are dynamic and interactive.
It holds information about the current state of the app. You can keep your variables and your data inside the local state of the React app by doing,
class App extends Component{
state = {
didUserLogin: false
}
}
Then, you can directly access the state using,
console.log(this.state.didUserLogin);
or update it with,
this.setState({didUserLogin: true});
As you keep manipulating the data inside the state, the components that use the state will be updated with the information you provided for the state.
More information,
https://thinkster.io/tutorials/understanding-react-state
https://reactjs.org/docs/state-and-lifecycle.html
class App extends Component {
constructor(props){
super(props);
this.state = {products: []};
}
render() {
console.log(this.state);
return (
<div className="container">
</div>
);
}
}
In the latest react, we now can define state as a plain JavaScript object and the render method gets it correctly. Here is an example of state as a plain object outside constructor:
In the latest react, we now can define state as a plain JavaScript object and the render method gets it correctly. Here is an example of state as a plain object outside constructor:
class App extends Component {
constructor(props){
super(props);
}
state = {products: []}
render() {
console.log(this.state);
return (
<div className="container">
</div>
);
}
}
More Details
https://www.codegreet.com/how-to-use-state-in-reactjs/

How to re render a static component in 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

Force render component 1 when i refresh component 2

I made a blog project in React. The array of objects (articles) are loaded from component 1. When i click the article title in component 1, and going on component 2 (entire article) everything is rendered ok. If i hit refresh, is rendered just component 2 and component 1 no, so i get TypeError: Cannot read property 'title' of undefined.
If i go back in component 1, everything is rendered and i can access again component 2. I use router dom.
How can i force render component 1 when i refresh component 2?
Here is my component 2:
render(){
return (
<div className="SinglePageContainer">
<div className="SinglePageTitle">{this.props.currentObject.title}</div>
<div className="SinglePageDate"><FontAwesome name="clock-o"/> {this.props.currentObject.date}</div>
<div className="SinglePageArticle">{this.props.currentObject.text}</div>
</div>
);
}
}
It seems like you are using a router and you have a route for Component1(ArticlesList) and a different route for Component2(Article) so the problem would not be that you need to render ArticleList one more time,ArticleList does the job of getting the data for Article when you start navigating from first route but if you want your second route to also behave as a different page Article component should fetch its own data.
I would suggest adding passing a fetchArticle property to Component2 that you can use in case there is no data loaded at the moment you try to render it. And also prevent rendering the article content until you receive the data for that article.
class Article extends React.Component {
componentDidMount() {
const { articleId, articleData, fetchArticle } = this.props;
if (!articleData) {
fetchArticle(articleId);
}
}
render() {
const { articleData } = this.props;
if (!articleData) {
return (<div>Loading</div>);
}
return (
<div>
{articleData.content}
</div>
);
}
}

How to refresh props with React/Redux when user enters a container

I have CompetitionSection which repeats all the competitions from database. When user clicks on one, it redirects him to a Competition Page, loads for a second and renders the page with all the details in it. So far, so good.
But when users goes back to the Competition Section and then click on the second competition, it instantly loads up the previous competition, 0 loading time.
From my point of view, what is failing is that the props of the component are not updating when I render the component (from the second time). Is not a router problem, which was my first instinct because I'm seeing the route.params changing acordingly, but the actions I dispatch to change the props are not dispatching. Here's a bit of code of said component.
class CompetitionPage extends React.Component {
componentWillMount() {
let id = getIdByName(this.props.params.shortname)
this.props.dispatch(getCompAction(id));
this.props.dispatch(getCompMatches(id));
this.props.dispatch(getCompParticipants(id));
this.props.dispatch(getCompBracket(id));
}
render() {
let { comp, compMatches, compBracket, compParticipants } = this.props
...
I tried every lifecycle method I know. component Will/Did Mount, component Will/Did update and I even set shouldUpdate to true and didn't do the trick. As I understand, the problem will be solved with a lifecycle method to dispatch the actions everytime an user enters Competition Page and not just for the first time. I'm running out of options here, so any help will be appreciated.
NOTE: I'm a newbie at React/Redux so I KNOW there are a couple of things there are anti-pattern/poorly done.
UPDATE: Added CompetitionsSection
class CompetitionsSection extends React.Component {
render() {
const {competitions} = this.props;
return (
...
{ Object.keys(competitions).map(function(comp, i) {
return (
<div key={i} className={competitions[comp].status ===
undefined? 'hide-it':'col-xs-12 col-md-6'}>
...
<Link to={"/competitions/"+competitions[comp].shortName}>
<RaisedButton label="Ver Torneo" primary={true} />
</Link>
...
It helps to better understand the lifecycle hooks. Mounting a component is when it is placed on the DOM. That can only happen once until it is removed from the DOM. An UPDATE occurs when new props are passed or setState is called. There are a few methods to troubleshoot when updates are not happening when you think they should:
Ensure that you are changing state in componentDidMount or componentDidUpdate. You cannot trigger an update in componentWillMount.
Make sure that the new props or state are completely new objects. If you are passing an object down in props and you are just mutating the object, it will not trigger an update. For instance, this would not trigger a update:
class CompetitionPage extends React.Component {
constructor(props) {
super(props)
this.state = {
competitions: [ compA, compB ]
}
}
triggerUpdate() {
this.setState({
competitions: competitions.push(compC)
})
}
componentDidMount() {
triggerUpdate()
}
render() {
return(
<div>
Hello
</div>
)
}
This is due to the fact that a new competition is being appended to the array in state. The correct way is to completly create a new state object and change what needs to be changed:
const newCompetitions = this.state.competitions.concat(compC)
this.setState(Object.assign({}, this.state, { competitions: newCompetitions }))
Use ComponentWillRecieveProps on an update to compare previous and current prop values. You can setState here if clean up needs to be done:
Read more about this method in the React documentation:
https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops

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>
)
}
}

Resources