ReactJS one time initialisation - javascript

I have a Component say HomePage where I'm calling getCurrentLocation to get the location using GPS. This value will be used to select a value from a Drop Down. User may then use the dropdown to change the value.
When I navigate away from this page and then come back using
const appHistory = createHashHistory();
appHistory.goBack();
the constructor and the componentDidMount are executed again. So the user selected value is lost and i get the default value again.
So where do I put by initialisation code? I come from Ionic where there something like ionViewDidLoad which is executed only when the page loads the first time. Is there an equivalent for this is React.
Below is my code
export class HomePage extends React.Component {
constructor(props){
super(props);
state = {
currentLocationCoordinates:[],
};
this.getCurrentLocation = this.getCurrentLocation.bind(this);
}
getCurrentLocation(){
navigator.geolocation.getCurrentPosition((success)=>{
console.log("Current Location: "+success.coords);
this.setState({
currentLocationCoordinates:[success.coords.latitude,success.coords.longitude],
userLocationCoordinates:[success.coords.latitude,success.coords.longitude]
});
});
}
}
componentDidMount(){
this.getCurrentLocation();
}
}

I would avoid using componentDidMount for this. Make your components as resilient to re-renders and re-mounts as possible.
By the sounds of it you are after an application level state container that will hold your application state regardless of whether your component is mounted or not.
Most of the React community relies on Redux for this although other state containers do exist. I'd suggest having a look at Redux and using it to hold those location details as part of Redux store. They will then be always accessible on your component as props, regardless of whether it re-renders or not.

You need to use ComponentDidMount() together with a flag that detects whether the component has been initialized or not. You are on the right track.
componentDidMount(){
initialized ? "" : this.getCurrentLocation();
}

Related

Why does changing Component props in App.js doesn't automatically refreshes it in browser when props are used in state of class component?

I have just started to learn React and want to understand the difference in props and state behavior. I have two files App.js and Counter.js.
App.js:
import Counter from './Counter'
function App() {
return (
<Counter initialCount={2} />
)
}
export default App;
And Counter.js:
import React, { Component } from 'react'
export default class Counter extends Component {
constructor(props) {
super(props)
this.state = {
count: props.initialCount
}
}
render() {
return (
<div>
<button>-</button>
<span>{ this.state.count }</span>
<button>+</button>
</div>
)
}
}
When I change initialCount in App.js and save file, it only changes in browser automatically if I have { this.props.initialCount } in <span></span>.
If I have { this.state.count } between spans (as in the code above), and try to change initialCount in App.js and hit save, then the value in doesn't change in browser. If I refresh the browser or change something in Counter.js after that and hit save (even adding simple space anywhere), then it updates the value without me having to refresh the browser.
I use Chrome and ReactDeveloperTools. From Components tab I can see that after I hit save in App.js, it changes props to the new value, but state is still the same.
It seems that constructor only called once. But I still don't understand this behavior.
Component's constructor is only called once, when component is created. So when you for example change initialCount programmatically, Counter's constructor would not be called again.
This is a feature of Hot Reloading which does not recreate Counter component when you change props in App, but behaves as props of Counter component are changed programmatically.
It seems like you are confusing two different things. One thing is a rerender on the change of data in React (say counter value changes onClick event) and the other is a manual change of hardcoded data in the application.
You seem to be describing a forced rerender with a change in your source code. It is most likely connected with the watcher tool that is set up by a tool that manages automatic updates during the development on a local server (Webpack / Create React App setup most likely). I tried to simulate in this sandbox but could not, as the counter value is always refreshed despite using state or props.
Also, FYI, beware of setting state with props. You can read this short post about it.

React changing state in Parent , does render calls for all its children and sub-children as iteration?

i am setting the language name in my local storage , when it changes from a dropdown in topbar , i want the whole current view to be re-rendered and words translated to the selected language. my layout is like this
render(){
return (
<MainContainer>
<TopBar/>
<SideBar/>
<RouteInsideSwitch/>
</MainContainer>
)
}
in render of components ,the words to be translated basically calls a function that returns the correct word based on the local storage language name.
i change the language and i set the state in maincontainer for selected langauge and set it in local storage. however i dont want to move that state from Maincontainer to all my components. also dont want to store it in redux because then all the possible containers have to listen to it and then pass it to their children as props.
what currently happens is that saving state in mainContainer without passing it to any children , the children does re-render but only the immediate ones , if there are more children in those children and so on , it does not re-render because i m not passing the state throughout the chain.
open to any suggestion based on different pattern for language changing. but my question is that is there any way to re-render the current open view (all components in dom).
If your concern is that you have a number of "possible containers" which all need to handle the state change, perhaps consider creating a higher order component that includes the common language rendering logic (your RouteInsideSwitch leads me to believe this may the issue). In that way, you can avoid duplicating that logic across a ton of "possible" components that all require the functionality of dynamic language rendering and will avoid the need to dial a bunch of components into a redux store, assuming they are in the same hierarchy.
const DynamicLanguageComp = RenderComponent => {
return class extends Component {
constructor(props) {
super(props)
//additional state setup if needed
}
changeLangFunc = () => { /* handle change */ }
render() {
return <RenderComponent handleLanguageChange={this.changeLangFunc} {...this.props} {...this.state} />
}
}
}
If you would like to avoid a re-render on certain intermediate components that may be receiving props by way of state change you can implement the lifecycle method shouldComponentUpdate(), which by default returns true. You can make a comparison of nextProps to your current props, and return false if a re-render is undesired despite new props.

How would a share the state of the same React component across multiple pages?

I have a React Component with a toggle on it (on or off). The on / off state is handled by the components own state (this.state).
But I want that state to remain when the user goes from one page to the next. For instance they are on home.html and then when user clicks to another page like about.html.
Also this is not a single page app. Do I want Redux or Mobox or some other state management tool? Suggestions are welcomed.
But I want that state to remain when the user goes from one page to the next.
As has been said in comments probably the most straight-forward way is to just store the state to localstorage and retrieve it when the component mounts.
class Toggle extends Component {
componentDidMount() {
const storedValue = localStorage.getItem("my_value");
if (storedValue) {
this.setState({ value: storedValue });
}
}
handleChange = e => {
const value = e.target.value;
this.setState({ value });
localStorage.setItem("my_value", value);
}
render() {
return ...
}
}
Also this is not a single page app. Do I want Redux or Mobox or some other state management tool? Suggestions are welcomed.
No, Redux and Mobx aren't necessary, they are state containers that have ways to persist to localstorage (for example redux-localstorage and mobx-localstorage), but the key is just persisting to localstorage.
If you are not moving pages (whole page refresh) and only using different components then you can simply define a state in parent component and pass it in the child components along with a function that would toggle the state.
Function would look like this:
ToggleState = newState => this.setState({ myState : newState });
Pass this function as prop to child component.
Use it in child component as
This.props.toggle(newState);
**but if it is across multiple pages the you can go for localstorage **
Hope this resolves your issue.

Does React Flux library Alt use React's state?

After completing the guide on the Alt site I am confused if Alt uses Reacts state to set properties? In part 3 - using Stores, it says
Instance variables defined anywhere in the store will become the
state.
It then puts a variable in the store:
this.locations = [];
Yet if I go into the main React component and log the state, after locations is given data of course, I get undefined except on the props?
loggState() {
console.log(this.state); // undefined
console.log(this.locations); // undefined
console.log(this.props.locations); // [object][object]..
}
Can anyone explain the relationship between states and props when using Alt?
In Alt—and indeed most Flux implementations—the store is a totally different part of your application to your components.
A component subscribes to changes in a store, then uses the changed data to update its local state, causing it to re-render.
We derive the initial state of components that use the LocationStore from whatever the store's state is when we instantiate the component.
getInitialState() {
return LocationStore.getState();
},
Then we set up a subscription, listening for changes to the store.
componentDidMount() {
LocationStore.listen(this.onChange);
},
And finally, we use the subscription handler to apply these changes to the component's local state. The way you decide to apply each update is totally up to you.
onChange(state) {
this.setState(state);
},
Each time we call this.setState with a new state, the component will re-render.
You could also use a higher-order component to subscribe to the store, then covert the store's state to props and pass them down to a wrapped component, instead. In which case, your component wouldn't need to be stateful at all.

do I have to use this.state in React to maintain component state?

I am unclear about the use of this.state in React components. While I can create this.state.myvar, why should not I just create this.myvar?
class MyComponent extends Component {
state = {myvar: 123};
render() {
return <span>{this.state.myvar}</span>;
}
}
or
class MyComponent extends Component {
myvar = 123;
render() {
return <span>{this.myvar}</span>;
}
}
I realize that there are helpers like this.setState, but at the end this.state is just a convenience, right? Or does it play a bigger role in React? Should I avoid setting properties directly on this to store my state? If so, why?
No, in fact; rather wrong.
this.state in a react component is a special React-backed container that is only acknowledged as having been updated when you use setState, which triggers a re-render, which might cause DOM updates (or not, depending on what React's diff algorithm sees happening in the JS virtual dom).
You can, of course, also use object properties bound to this, but changing them does absolutely nothing for the component itself. React doesn't look at your full component instance for changes, it only looks (internally) at the state, and (when changed by parents) at the props.
As such, you can't "create" things like this.state.myvar and then expect them to actually exist from lifecycle function to lifecycle function: as a special management construct, any values you tack onto state outside of proper this.setState(...) calls have undefined behaviour. They might exist, or they might not. If you really are working with the internal state, then you need to signal changes via this.setState({ myvar: value }).
Of course, that doesn't mean you can't use this.myvar, that'll work fine, but changing it will not "do" anything other than literally just that.
When would you use this.val instead of state? When your component has to perform operations that lead to an "intermediate" state, neither being one renderable state, nor the next. For instance, when code can update a state value multiple times between renders, during those changes your component is in an intermediate state, and so you don't want it to re-render. In fact, expecting it to can lead to huge bugs:
...
doTest() {
this.setState({ val: this.state.val+1 });
this.setState({ val: this.state.val+1 });
this.setState({ val: this.state.val+1 });
},
...
This code will not yield a this.state.val that's 3 higher than before, because state updates are queued, and overwrite each other. Only the last instruction before a re-render "wins". So in that case you'd need something like:
...
doTest() {
var localval = this.state.val;
localval++;
localval++;
localval++;
this.setState({ val: localval });
},
...
And then if we also need that value accessible outside of this function, then we finally have a legitimate use for a this property:
...
doTest() {
this.accessibleval = this.state.val;
this.updateValueAFewTimes();
this.setState({ val: this.accessibleval });
},
...
this.state plays a larger role than you realize.
Setting state via this.setState triggers the component to re-render (among other things). Otherwise, React would have no way of knowing when something it depends on changed.

Categories