Category: React Native

Git : Don’t commit node_modules except a file in a library

If you are using the node_modules in your Node.JS / Javascript / Typescript project you should exclude to commit all the libraries used by your application with this line in the .gitignore file:

.gitignore

node_modules/

But, you may need to modify a file in the /node_modules folder, excluded in the .gitignore

Force commit a file in a excluded folder in .gitignore

If you want to fix a file in a library that makes some problems in your application, you may want to modify the library directly in /node_modules (the case you are using the last version of the library, you can check on https://www.npmjs.com/ if you are using the last version in your package.json)

In my case, I modified node_modules/react-native-firebase/ios/RNFirebase/notifications/RNFirebaseNotifications.m a library that is not changed since 2 years and have a problem in my application. You can of course make a git issue on the official page but if you need it to work fast, you may want to commit it directly in your project and it is fixed.

After you made the change in the library, you can commit with git add -f …

In my case:

git add -f node_modules/react-native-firebase/ios/RNFirebase/notifications/RNFirebaseNotifications.m
You can see your file to be commit in your Git Desktop, and my node_modules folder is excluded in .gitignore

Mac M1 : react native iOS mobile app on Simulator

I decided to make an article because I spent almost 5 days on this problem, and I don’t want it never happen. So let me help all the people that can be in the same case of me.

– You have a Mac M1 running on ARM 64 architecture
– You are working on a React Native or Swift project with Xcode

Exclude the ARM architecture in the Podfile

Add the following lines in the Podfile (/ios/Podfile) :

    post_install do |installer|
      ## FIX MAC M1 ARM
      react_native_post_install(installer)
      installer.pods_project.build_configurations.each do |config|
        config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
      end
    end

You should check that there is only one “post_install” in the file, if there is not you can add it at the end of the file, if there is already “post_install” somewhere, just put the instructions to exclude the architecture ARM 64 at the end of the “post_install” section.

Dependencies with CocoaPods

In the /ios folder of your React Native project, you should run the following command to build all the dependancy in the /Pods folder :

sudo arch -x86_64 pod install --allow-root

or, you can also use pod-install to be sure all is installed:

npx pod-install

In case of error: Delete /Pods folder, delete Podfile.lock and start again. In case of error of dependancies in node_modules, delete node_modules and run yarn.

Exclude the ARM architecture in Xcode

Now, you should also exclude the architecture in the project settings in Xcode :

Exclude the architecture “arm64” in Project > Build Settings > Architectures

Then if you start the react native project on Simulator it should works !

Public Images for your React / Angular app on Google Cloud

We often need images in our React or Angular app, but putting them in the project is not clean.
So we can use Google Cloud with Cloud Storage for the images on your app.

There are many advantages of using Cloud Storage to expose public images :
– Real time maintenance (upload, delete, change, …)
– You don’t need any commit on your git (if you commit images on your Github / Gitlab for example)
– Clean project, only code files
– Light project repository to commit, images are heavy quickly

Create a Bucket

First, you need to create a Bucket (it’s like a big folder) if you don’t already have one.

Switch to Uniform access control

Then, to make your Bucket public, go to the Permissions tab, and change the access control to Uniform :

You should click Switch to Uniform, so you don’t have to make public each file one by one
You can see, if you upload your first image, that it’s not public yet

Add public access using by adding a Reader role for allUsers

You can then add the access of Object Reader to allUsers
Then you can see it’s Public to Internet and you are able to copy URL

You can now use you image anywhere, it’s on internet and anyone can see it with the URL, so you can use it to store images for your React / Angular app, all images will work.

OnClick inside OnClick with React

While doing some test after putting the event OnClick in a DIV inside another DIV with the Onclick event, I was not able to trigger the OnClick event that was inside the other.

<div id="div1" style={{background: 'red'}} onClick={() => { 
setClicked('div1');
}>
  DIV 1
  <div id="div2" style={{background: 'green'}} onClick={() => { 
  console.log('you clicked div2');
  setClicked('div2');
  }>
    DIV 2
  </div>
</div>
When we click on the DIV 2, it triggers the DIV 1 onClick event

If you click on the green div, and then, if you check the logs you see that the log is working, you triggered the event.
But, if you check your state, you will see that it’s div1, and not div2, but you clicked DIV 2.
Your click action has been propagate to the DIV 2.

How to solve the problem

In order to solve this problem, we will need a fix. So we can trigger both events.
The problem is that the click action is propagate to the the other div.
So, we need to check when you trigger the onClick action that the user clicked on the good one.
To do so, we can add the following instructions in the inner DIV:

if(event.target !== event.currentTarget) return;

Which will give:

<div id="div1" style={{background: 'red'}} onClick={(event) => { 
if(event.target !== event.currentTarget) return;
setClicked('div1');
}>
  DIV 1
  <div id="div2" style={{background: 'green'}} onClick={() => { 
  console.log('you clicked div2');
  setClicked('div2');
  }>
    DIV 2
  </div>
</div>

With buttons inside a DIV with 3 levels DIV

If you have 3 levels of DIV and you want only the action of the button of the div the be triggered then you can use the following instruction in the end of the OnClick:

<div id="div3" style={{background: 'yellow'}} onClick={(event)=>{
...
event.stopPropagation();
}}/>

stopPropagation will stop the click event and so the second OnClick event will not be triggered.

React.JS / React Native : Class VS Hooks

No matter if you are using React.JS or React Native, Javascript or Typescript, you can choose these 2 ways to manage the states.

Using Class OR using Hooks : What are the differences ?

Class

import React, { Component } from 'react'; 

[...]

class Button extends Component {
    constructor(props){
        super(props);

        this.state = {
            touched: false,
            selected: false,
        }
    }

  toggleTouched = () => {
    this.setState({
      touched: true
    });
  } 
    
    render(){ 
        return( 
            <button id="button" onMouseOver={this.toggleTouched} >
                click me!!
            </button>
        );
    } 
}

export default Button;

Using a class, you need to create a class that extends from a React Component. Like every class in every languages, you use the constructor to init the class. We use it to set the default values to our states. Moreover, we need to use “this” in that class to know that we are getting the values or the function in this class, this refer to the context.


Hooks

import React, { memo, useState, useEffect } from 'react'; 

[...]

const Button = memo((props) => {
  const [touched, setTouched] = useState(false);
  const [selected, setSelected] = useState(false); 
 
  const toggleTouched = () => {
    setTouched(true);
  } 

  return( 
     <button id="button" onMouseOver={toggleTouched} >
        click me!!
     </button>
  );
}); 

export default Button;

Same component, working the same too, but we need a bit less code.
We don’t need a constructor, to set the default value to our states, we just use the parameter of useState.
We don’t need the “this” keyword too, because we don’t are in a class anymore.

Instead of using setState, we use useState.
When it starts if “use…”, we are talking about hooks :
– useState : set a state with the name, the setter, the initial value
– useEffect : refresh if specific state is changed, we can use it as “ComponentWillMount” if we don’t give a state in 2nd param
– useRef : Reference for JSX
– useCallback, …etc.

Hooks seems to be the new best way to manage our states and you should use it as it may save a lot of times and lines in your code.

Create a dynamic list from JSON • React Native / React.JS

How can we create a dynamic list of objects like Views or Texts, dynamically, in a loop in React Native or React.JS from a JSON response from a REST API ?

The objective is to create a dynamic interface with buttons for adding and removing elements like that :

First, we will use the data variable to store a JSON reponse (later you can change it with the API response with a fetch() function), it will contains 3 elements.

[
        {
            "id": "01",
            "name": "Charlie",
        },
        {
            "id": "02",
            "name": "Tango",
        },
        {
            "id": "03",
            "name": "Delta",
        }
] 

Then, we will create the json variable to store the parsed JSON from the data variable. It means, the data variable is only a text string and the json variable is a JSON object, so we can do json[0].id for example.

We can put the json variable as a state so if the JSON changes, the UI with refresh automaticaly.

Here is what it should look likes in your code, in the constructor of your class :

export default class DynamicList extends React.Component {
  constructor(props) {
    super(props);

    let data = `
    [
        {
            "id": "01",
            "name": "Charlie",
        },
        {
            "id": "02",
            "name": "Tango",
        },
        {
            "id": "03",
            "name": "Delta",
        }
    ]`;

    let json = JSON.parse(data);
    console.log('json ', json);

    this.state = {
      list: json,
    };
  } 

[...]

Now, to display a list from the state list (it will be this.state.list), we will use the map() function in render(), before the return, to create as many objects that we have elements in the list array.
In your map() function, you will have 2 parameters : data and i. You will have to put the i, the incremental variable, as a “key” in each object you will return as a new element – here, it’s <TouchableOpacity> :

render() {
    // HERE WE MAKE OUR LIST OF OBJECTS
    const soldierList = this.state.contracts.map((data, i) => {
      return (
        <TouchableOpacity
          key={i}
        >
          <View
            style={{
              flexDirection: 'row',
              justifyContent: 'flex-start',
              paddingTop: 5,
              paddingBottom: 5,
            }}
          >
              <Text style={{ fontFamily: 'Gotham-Medium', color: '#8DA8C7' }}>
                {dateShort(data.datestart)}
              </Text>
            </View>
            <View style={{ flexDirection: 'row', right: 0, position: 'absolute', bottom: 5 }}>
              <MaterialCommunityIcons
                name="cross"
                style={{ color: '#0261D2', lineHeight: 20 }}
              />
            </View>
          </View>
        </TouchableOpacity>
      );
    });

    // NOW WE CAN DISPLAY IT, IF THE LIST IS EMPTY WE GOT THE EMPTY LIST MESSAGE
    return (
      <ScrollView style={{ backgroundColor: '#f6f6f6', height: '100%', width: '100%' }}>
        {this.state.list.length < 1 && (
          <View style={{ alignItems: 'center' }}>
            <Text style={{ fontWeight: 'bold', color: '#0361d2', fontFamily: 'Gotham-Medium' }}>
              Empty list !!!
            </Text>
          </View>
        )}
        {this.state.list.length >= 1 && <View>{soldierList}</View>}
      </ScrollView>
    );
  }  

UPDATE (SOLUTION 2)

We can optimize it by testing directly the length of the array, making less code in the return :

render() {
     // HERE WE MAKE OUR LIST OF OBJECTS
     const soldierList = this.state.contracts.length ? this.state.contracts.map((data, i) => {
      return (
        <TouchableOpacity
          key={i}
        >
          <View
            style={{
              flexDirection: 'row',
              justifyContent: 'flex-start',
              paddingTop: 5,
              paddingBottom: 5,
            }}
          >
              <Text style={{ fontFamily: 'Gotham-Medium', color: '#8DA8C7' }}>
                {dateShort(data.datestart)}
              </Text>
            </View>
            <View style={{ flexDirection: 'row', right: 0, position: 'absolute', bottom: 5 }}>
              <MaterialCommunityIcons
                name="cross"
                style={{ color: '#0261D2', lineHeight: 20 }}
              />
            </View>
          </View>
        </TouchableOpacity>
      );
    }) : (
      <View style={{ alignItems: 'center' }}>
        <Text style={{ fontWeight: 'bold', color: '#0361d2', fontFamily: 'Gotham-Medium' }}>
          Empty list !!!
        </Text>
      </View> 
    );
 
    // NOW WE CAN DISPLAY IT, IF THE LIST IS EMPTY WE GOT THE EMPTY LIST MESSAGE
    return (
      <ScrollView style={{ backgroundColor: '#f6f6f6', height: '100%', width: '100%' }}>
        {soldierList}
      </ScrollView>
    ); 
 } 

Alert confirmation message for sensible actions

Hello everyone,

In your application, is it possible that you made a settings page where the user can edit and remove things inside your app. For example, let’s say there is a button to remove definitely the user account and all his data. We can say that this type of operation is sensible and should be verified.

When the user click on the button “Delete my account”, we will display a message of confirmation “Do you really want to remove your account ?”. If he click DELETE, we will remove it, if not, we will close the message. Simple as that.

In our code, we will first import alert :

 import { ... , Alert } from 'react-native'; 

Then, you we create a function “deleteAccount” called when the “Delete my account” button is pressed :

  <Button onPress={ () => { this.deleteAccount(); } } title="DELETE MY ACCOUNT"/> 

Inside deleteAccount, we will put our Alert message :

How to use WebSockets • React Native

It can be very simple to do GET, POST, PUT and DELETE requests with React Native (see the official Expo documentation https://docs.expo.io/versions/latest/react-native/network/), therefore, those requests are not interesting when we want to do a chat for example (we can talk about “real time events”).

To do it, you need first to create a WebSocket server. It won’t be on the phone, because usually the phone is only the client.

You can create a simple WebSocket server with this Perl library : https://metacpan.org/pod/Net::WebSocket::Server
Only few lines are necessary to make your WebSocket server running.


In your App.js, you can add the IP of your server in a global variable at the top of your file :

Then in your constructor you can add the WebSocket( WS_ADRESS_SERVER_STRING ) Javascript object, so the websockets will be listen when the application is starting.
You can add the 4 events onopen, onmessage, onerror, onclose :

Now you should add ws.send() to send data inside your code or inside your UI with onPress.

Hide and show blocks of content • React Native

While creating single page application or making dynamic forms, is it important to show or hide parts that we want the user to see or not.
We simply do this by adding variables in the constructor of the class :

this.level and this.status

Inside functions of the class we will modify the variables this.level and this.status.
We will display content by testing the value of those variables.
To do it, we will add { this.VARIABLE == VALUE && before the content we want and } at the end. For example :

How to get input text • React Native

In this article we will see how to get the user input text inside the <TextInput>, very simply.
In this example, we will be using a login page :

Login page

Add the reference for each TextInput at the top of your login class, inside the constructor :

Add references with React.createRef()

Then, put the ref tag inside the each TextInput.
Attribute this ref tag to each variable that have been referenced. Here is the example with this.logInput :

add the ref tag

Now you can get the value by using this.logInput.current._lastNativeText inside our code.