Can I setState in the static method with react native? - react-native

I have a static method in my component as follows:
static updatestate(totalCount,totalCost){
this.setState({totalCount,totalCost});
}
I only have to make the static method to pass data to the component.but as you know we can't use this in the static methods. Is there any way to pass data to a non-static method, without creating a new instance and without creating props. as following:
import MyComponentName from './MyComponentName.js';
MyComponentName.MyMethod(params)
Thanks.

As you state, you can't use this in static methods.
If you are trying to invoke a method on a specific component instance, use a ref to that instance. Suppose you wanted to invoke updateState on this component:
class ChildComponent extends React.Component {
state = {totalCount: 0, totalCost: 0};
updateState = (totalCount, totalCost) => {
this.setState({totalCount, totalCost});
}
render() {
const {totalCount, totalCost} = this.state;
return <Text>totalCount: {totalCount} totalCost: {totalCost}</Text>;
}
}
You would get a ref to an instance, and can then call updateState:
class ParentComponent extends React.Component {
render() {
return (
<View>
<ChildComponent ref={child => {
this.child = child; // gets a ref to the child component
}} />
<TouchableOpacity onPress={() => {
const {totalCount, totalCost} = this.child.state;
this.child.updateState(totalCount + 1, totalCost + 10); // call method on child component
}}><Text>press</Text></TouchableOpacity>
</View>
);
}
}
(If instead, you want to setState on all instances of a component, you might be better offer using a React.createContext Provider that the ChildComponent's could be a Consumer of).

Related

How to mock React Functionnal Component method?

I don't found a lot of jest&enzyme mock/spy example when react components are functions instead of class...
Since it looks impossible to spy on functionnal components method with "jest.spyOn" like it's possible to do with class components, is there a better or other way than passing method reference in props like my example below ?
it('click on connect button', () => {
let handleConnect = jest.fn();
let shallowLogin = shallow(<Login handleConnect={handleConnect} />);
//const spy = jest.spyOn(shallowLogin.instance(), 'handleConnect');
//Impossible to spyOn like this ?
let button = shallowLogin.find('Styled(Button)');
button.simulate('press');
expect(handleConnect).toHaveBeenCalledTimes(1);
});
I hate to do this because it's intrusive on the component code and it force the change stuff inside for the tests...
Component example :
import useForm from 'react-hook-form';
export default function Login(props) {
const {register, handleSubmit, setValue} = useForm();
const onSubmit = data => {
console.log('data: ', data);
if (FormValidation(data, "login")) {
props.navigation.navigate('App');
}
};
return (
...
<Button style={styles.button} rounded large onPress={handleSubmit(onSubmit)}><Text
style={styles.buttonText}>{locale.t('loginScreen.CONNECT')}</Text></Button>
...
);
}

how to call fetch in a sub component in react native?

I saw some tutorials online and majority of the examples are using
a class component e.g
export default class App extends Component {
constructor() {
super();
//set state here and data source
}
componentDidMount() {
//get json data here
}
render() {
return(
blah blah blah
)
}
}
what if I want a sub component to have a functionality that calls fetch , how to do it ?
//NewComponent.js
//this is my sub component
const NewComponent = () => {
return(
<FlatList />
//I want a list of data here
)
}
const getData = () => {
//call fetch here
}
export default NewComponent
so in my second code snippet how to call the getData in order for me to display the data inside the NewComponent?
You have several options. Personally I would go for #3
You can make your sub component a class and use React's lifecycle method such as componentDidMount
You can move getData function to another javascript module. Then import and call it from parent component. Pass the result as props down into the sub component.
Use React's Effect Hook. Pay attention to the section Optimizing Performance by Skipping Effects also.
Hope that helps.

how to manage component mount and unmount to update state values?

I would like to know how to manage state property when the component mounts and unmounts.
I have a lot of different components in my application to maintain the application flow. I know about function componentdidmount and componentWillUnmount. and I also tried the solution about _isMounted=true on componentdidmount function and check _isMounted properties value when I update setState and then update _isMounted=false on componentWillUnmount function.
but this won't work when more two components come in the picture.
For example following links:
https://www.robinwieruch.de/react-warning-cant-call-setstate-on-an-unmounted-component/
Is there a way to check if the react component is unmounted?
as per the example, I have made a common class which will update the value of a component in setMounted function and will return value in getMounted function to validate component is mounted or not. These methods work correctly on a single screen when I call another screen from a stack and update some values then comes back on the previous page and refresh page it will ismount=false.
class Mount {
isMounted=false;
getMounted=()=>{
return isMounted;
}
setMounted=mounted=>{
isMounted=mounted;
}
}
var mount=new Mount();
export default mount;
class example extends component{
componentDidMount=async()=>{
mount.setMounted(true);
await this.loadScreen();
this.willFocusSubscription = this.props.navigation.addListener(
'willFocus',
async() => {
await this.loadScreen();
}
);
}
loadScreen=async()=>{
//some other stuff
if(mount.getMounted()){//second time value is false
this.setState({value:'value'});
}
}
componentWillUnmount() {
mount.setMounted(false);
}
//renderview where i call example2 on buttonclick
}
class example2 extends component{
componentDidMount=async()=>{
mount.setMounted(true);
await this.loadScreen();
}
loadScreen=async()=>{
//some other stuff
if(mount.getMounted()){
this.setState({value:'value'});
this.props.navigation.goBack();
}
}
componentWillUnmount() {
mount.setMounted(false);
this.willFocusSubscription.remove();
}
}
It was showing following warning before using mount functions:
Can't perform a React state update on an unmounted component
You are creating only a single instance of your Mount class that is exported and shared across every instance of every component. You will need to create a new instance of Mount for each component instance:
class Mount {
...
}
// export the Mount class
export default Mount;
class example extends component{
constructor(props) {
super(props);
// create an instance of Mount for each component instance
this.mount = new Mount();
}
componentDidMount=async()=>{
this.mount.setMounted(true);
await this.loadScreen();
this.willFocusSubscription = this.props.navigation.addListener(
'willFocus',
async() => {
await this.loadScreen();
}
);
}
loadScreen=async()=>{
//some other stuff
if(this.mount.getMounted()){//second time value is false
this.setState({value:'value'});
}
}
componentWillUnmount() {
this.mount.setMounted(false);
}
//renderview where i call example2 on buttonclick
}
Notice the addition of the constructor and the use of this.mount instead of mount throughout.

Navigation - Pass variable to other files

I'm new on React-Native and it's my first React-Native app. However, I have already some problems.
I want to pass a variable from one class (Home.js) to an another. (Is it possible without using the composent in the render() fonction ?)
##### Home.js #####
class Home extends Component {
constructor(props) {
super(props);
this.state = {direction: "defaultvalue"};
}
getCurrentDirection() {
return this.state.direction;
}
render() {
/***..... some elements ..*/
}
}
export default Home
And
#### Two.js ####
import Home from './Home'
/** SOME CODE **/
const DrawerOptions = {
initialRouteName: Home.getCurrentDirection(),
contentComponent: CustomDrawerContentComponent,
drawerWidth: 300,
};
However it doesn't work... How to resolve it ? I have already try some solutions as declare the getCurrentDirection as static but nothing.
In addition, it seems to be a specific case because DrawerOptions is not a class. Could you please, add to your response also, how make it if I want to obtain the variable into the class Two.js ?
I meant if Two.js was for example :
##### Two.js #####
class Two extends Component {
var myvariable = Home.getCurrentDirection();
render() {
/***..... some elements ..*/
}
}
Thanks a lot in advance
A recommendable way of accessing the state from a component into another is to use (in this case) the Home component as a parent of Two component. This way you don't have to trigger a function to access the Home's state. On each time when the state of the parent (in this case) component will be updated, the Two component will receive the updated property (direction). If you want to call a function from Two component, you have to pass it a function as a property (changeCurrentDirection) that will call back the function you want to trigger from Home component.
So you would have something like this:
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
direction: "defaultValue"
};
}
changeCurrentDirection() {
this.setState({
direction: "valueChanged"
})
}
render() {
let state = this.state;
return (
<Two
direction={state.direction}
changeCurrentDirection={() => this.changeCurrentDirection.bind(this)}/>
)
}
}
class Two extends React.Component {
render() {
let props = this.props;
return (
<div>
<h3>{props.direction}</h3>
<button onClick={props.changeCurrentDirection()}>Change value</button>
</div>
)
}
}
React.render(<Home/> , document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/react.min.js"></script>
<div id="app"></div>
Additional info you can find here.
Also, if you want to have a good management of the state of your components, my advice for you is to use redux. Using this library you can easily connect the component's actions and properties that can further be accessible from other files where you can manage them.

Pass variable from one component to another one in react native

I have ChooseLevel component which has many buttons. Once I click a button onLevelSelected function is being called and it call action creator which will return an action type, moreover it will redirect me to qPage component. In qPage component I make some calculation and I put the result in total variable.
Here's my code:
ChooseLevel.js
class ChooseLevel extends Component {
constructor(props) {
super(props);
}
onLevelSelected(levelNumber) {
this.props.levelSelected(levelNumber);
}
render(){
<Button key={1} onPress={this.onLevelSelected.bind(this, 1)}>
<Button key={2} onPress={this.onLevelSelected.bind(this, 2)}>
<Button key={3} onPress={this.onLevelSelected.bind(this, 3)}>
....
}
}
My action creator looks like this:
import { Actions } from 'react-native-router-flux';
export const levelSelected = (levelNumber) => {
return (dispatch) => {
dispatch({
type: 'level_selected',
payload: levelNumber
});
Actions.qPage(); // redirects me to qPage component
};
};
qPage.js
class qPage extends Component {
constructor(props){
...
}
calc(){
.... some calculation
total = result of previous calculation
}
render(){
....
....
}
}
How do I pass total variable from qPage to ChooseLevel page?
What you need to do is, i will go step by step:
1) create one more action and pass calculated value inside that action.
2) access that calculated value through props(reducer)
3) You can use componentWillUpdateProp(nextprops), Inside this fuction assign this new prop to the state of the class.
Cheers :)