ComponentWillMount can't find an variable - javascript

I have already created a react native CLI project. Now every time when user come to my screen I want to update some value. In my home screen, I have three top tabs. When the user clicks on the 3rd tab. I need to update some values every time.
For those three tabs, I am using: ScrollableTabView
import ScrollableTabView, { DefaultTabBar } from 'react-native-scrollable-tab-view';
I used this below code for every time to update the values. But this is calling only for one time:
useEffect(() => {
alert('i called');
})
Then i tried :
import React, { useEffect, Component } from 'react';
componentWillMount( () => {
alert('called ');
})
But I am getting error like cant the variable componentWillMount.
How can I solve? Please help.
Thanks.

It seems like you are using the new React Native way by using hooks and functional components only.
It is not possible to use reacts lifecycle methods anymore - you will have to write your own componentWillMount code. Take a look at the docs or take a look at this answer:
How to use componentWillMount() in React Hooks?
~Faded

So, going back to React basics. There are 2 ways of declaring a component: using a Class based component or using a functional component which you are clearly using.
Before React Hooks, we couldn't have state in our functional components, that means that you cannot use the LifeCycle Methods from a Class based Component. I really suggest you to read the documentation. Instead, we can use hooks to get the same behavior.
Now, the useEffect hook will receive 2 parameters: the first one is the callback we are going to execute, and the second is an array of dependencies that will trigger that hook. It means that the hook will watch for changes in the variables you put in your array. Since you are not declaring an array of dependencies, the hook will be executed on every render.
So, what's exactly the problem? The problem is that declaring your tabs with react-native-scrollable-tab-view won't unmount the components for each tab, there are no variations, that's because your alert log is only being logged once. Because there are no more renders, just once.
Looking at the docs, you might be using onChangeTab method, which apparently will be called when changing the tab.

Related

NextJS- How to execute some codes just once in useEffect in React.StrictMode children?

I have a problem. Im developing a nextJS app. React renders my components twice. I know it is because of StrictMode. But in React and nextJS document i found that they strongly suggest us to use StrictMode. But in a part of my app that i am working on, i use useEffect and i want some codes in useEffect run just once not twice! Because runing codes there twice, make a bad bug. So How can i do that? How can i do something to make react run some codes in useEffect once? And i placed [] as a dependency of useEffect but it didnt work! For example something like this:
`//inside a component that is a child of React.StrictMode
useEffect(() => {
/* strict mode cuses adding something to body twice. I want to add it just once and without using cleanup function */
document.body.appendChild(something)
//it runs twice, too. I dont want it!
console.log('test')
}, [])
`
Thanks for helping!
The general recommendation is that every effect should return a "cleanup" function, and the initial effect + cleanup should be a no-op (and thus effect->cleanup->effect = effect). In your case, you could remove the appended DOM node in the cleanup:
useEffect(() => {
const node = document.body.appendChild(something)
return () => document.body.removeChild(node);
}, [])
The goal of strict mode is to catch issues like this for future versions of react where effects may run twice in weird cases (React may unmount and remount the component, and the bug would appear).
What if you made something a dependent of the useEffect function so that it only runs it when that 'something' changes? Unfortunately rendering twice to flush out side effects is just how strict mode works and there isn't a good way around that. I don't really always use it though even though it is recommended, and I am a big nextjs user.

Created hook not running again when pushing the same route with a new query

I have a component with a created hook like this:
created() {
if (this.$route.query.q) {
//fetchdata
}
}
However within the same component I try doing $router.push(`?q=${search}`) and the URL changes but the created hook doesn't rerun.
Vue will reuse the component if you re-route to it, so created won't run again. You can force it to do so with a key on the <router-view>:
<router-view :key="$route.fullPath" />
or use the beforeRouteUpdate hook:
beforeRouteUpdate(to, from, next) {
if (this.$route.query.q) {
//fetchdata
}
next();
}
This hook won't run when the component is first created, so with this solution you may need to use both created and beforeRouteUpdate.
Some differences:
With the key solution, the component won't be cached so it will be recreated on each route (which is what causes created to run each time). Maybe you wouldn't want that if you needed to do something only once in created such as calling an api only once regardless of the query. Or in rare cases maybe there would be a performance implication to recreating (probably not).
With beforeRouteUpdate you may have to use the same logic in 2 lifecycle hooks, but that's not really a problem. You can also reroute from this hook, which might be useful.
Use whichever one you prefer / makes more sense, as long as you understand the differences.

Where to make API hits ComonentDidMount or in ComonentDidUpdate [React.JS]

In an interview, an interviewer asked me that where should you make API-hits in a simple react application? Meaning in which life-cycle method in a Class-Component. I knew the answer to be ComponentDidMount - because it is the first life-cycle method where we get complete rendered dom meaning dom is now ready!
Then he asked, but why NOT in comonentDidUpdate?
Now, I told him what I had read somewhere, I don't know the exact answer of this -- except ComponentDidMount runs first, so make it there.
Now, can someone tell me if my answer was correct? Or should we make API-hits in ComponentDidUpdate()?
I am confused. Kindly, someone explain with reasoning? Thanks in Advance!
It depends on when you want to call the API:
If an API call is done only once then do componentDidMount
If after render based on some state, you want to fetch data again then do it in componentDidUpdate
EDIT:
Same scenarios can be handled within functional components using useEffect hook as follows:
1- Only runs the first time when the components render same as componentDidMount:
useEffect(() => {
// Run only once when the component renders
}, []); // Pass empty array as dependencies
2- Run every time when component renders either by props change or by local state change same as componentDidUpdate without comparing previous and current props:
useEffect(() => {
// Run every time the component re-renders including the first time
}); // Do NOT pass array dependencies
3- Run only when particular props change, same as componentDidUpdate but with props comparison:
useEffect(() => {
// Run only when the component prop1 and prop2 changes
}, [prop1, prop2]); // Pass props as array dependencies
Reference: Using the Effect Hook
Lets take an example scenario.
You have a profile page and it has a text box which allows you to update tags.
You do a fetch for the whole profile in the componentDidMount to get all the details and show the content.
And then componentDidUpdate will have to be used for something like the update on tags, lets say you do a fetch to get tags based on the user input for every 3 letters the user type. then you use componenDidUpdate to check the state and do the call.
If you think of the same in functional components we'll have to use useEffect.
useEffect(()=>{},[]);
See the array of dependecies, if you pass an empty array it would act similar to componentDidMount.
And the componentDidUpdate
useEffect(()=>{},[tagText]);
Here the effect will run only when a change it done to the tagText, but the componenDidUpdate would be different as you will have to compare the previous state and decide whether the text is updated.
According the Official React Documentation (Link):
componentDidMount
componentDidMount() is invoked immediately after a component is mounted (inserted into the tree). Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request.
This method is a good place to set up any subscriptions. If you do
that, don’t forget to unsubscribe in componentWillUnmount().
componentDidUpdate()
componentDidUpdate() is invoked immediately after updating occurs.
This method is not called for the initial render.
Use this as an opportunity to operate on the DOM when the component
has been updated. This is also a good place to do network requests as
long as you compare the current props to previous props (e.g. a
network request may not be necessary if the props have not changed).
Check out this link for a complete big picture. This will be handy while learning react.

React componentWillUpdate getting called twice

Iam new to React and i came across with this doc. It says that:
Either way, it is unsafe to use componentWillUpdate for this purpose
in async mode, because the external callback might get called multiple
times for a single update
How is it possible for the componentWillUpdate to be called multiple times? It doesnt explain it.
Thank you
Any change that is supposed to trigger a render will first go through a componentWillUpdate lifecycle. The change change can be a parent re-render causing the child to re-render, a change in components props, or a change in state.
However from v16.3.0 this lifecycle method is deprecated and it is encouraged that any sideeffect be handled in componentDidUpdate which will be triggered after render method.
On async mode, your component update/render may be postponed so react can deliver some hi-priority stuff. This means willUpdate will be called each time react starts working on your component, but it might not finish the full update, hence calling willUpdate every time it starts working on this component but only calls didUpdate once, after this process is finished.

Render after componentWillReceiveProps and before componentDidUpdate

Here's my problem:
I'm new at reactjs and I'm trying to make this app using SWAPI (swapi.co). For now I need to list characters and some info about them. The problem is I have this component called SelectedCharacter that returns some info about a character that was selected in a div.
The moment a character is passed through props to this component, I get a response via xmlhttp and the info is displayed. The thing is that I want to put a "Loading..." message while the data is fetched. This is how I was trying to figure it out:
I set up the componentWillReceiveProps function, where I test if I'll need to load stuff and the componentDidUpdate, where I fetch the data from this api and update the status.
I know, from react life cycle, that a render is called between componentWillReceiveProps and componentDidUpdate, and it indeed is.
I expected, then, that if I did this:
render() {
if (criteria) {
return <div>Loading...</div>
}
}
The thing is: even if this criteria is true (I tested it using console.log()), the message doesn't show until the next re-render. Am I doing anything too wrong here? If it helps, my code is at github.com/piubellofelipe/StarWars, the problem is at the selected_characters.js, in the src paste.
Thanks
I've been looking at your code, trying to work this out for you and I don't have any concrete answers for you, but I've noticed a few things that may be making things a bit unpredictable.
1. Calling forceUpdate
componentWillReceiveProps(){
this.setState({loading:true})
this.forceUpdate();
}
Calling setState will trigger a render, so the call the forceUpdate is not required here. This means there are more renders occurring than you might expect.
I believe this may be the cause of your issue for a pretty complicated reason. From the setState docs
... setState() is also asynchronous, and multiple calls during the same cycle may be batched together.
And from the forceUpdate docs
Calling forceUpdate() will cause render() to be called on the component...
My theory is that the call render triggered by setState, asynchronously setting loading to true, is being delayed and the one from forceUpdate is sneaking in first, while loading is still false.
2. Updating props
this.props.selected.moviesList = moviesListNames;
Components should never, ever, update their own props. Usually, this would be stored in state instead.
For more details on this, read this section of the docs and this answer.
3. Importing axios, but not using it
import axios from 'axios'
This one isn't really an issue (other than an unused import), and might just be preparation for where you're heading. axios gives a much nicer developer experience than XMLHttpRequest (in my opinion) for http requests and will clean up the fetchData function a lot, which will make troubleshooting easier.
I hope this helps a bit, and you're enjoying React. Feel free to follow up on any of these points in the comments or as new questions.

Categories

Resources