DEV Community

Cover image for Data Binding in React
Arkar Kaung Myat
Arkar Kaung Myat

Posted on

Data Binding in React

It was 2018 ,I remember that at that time, I have been coding some Python codes especially django and I already did some projects. And at that time the only language I know was Python, started as a backend developer building apis with Django.
And I know a little bit of HTML and CSS and I was not very good at it.Out of nowhere, let's just say I cannot keep up with the Zen of Python and I feel like with all these templates,models and all that in Django,I am feeling the real pain in the a**.
So I decided run away from python and asked my brother who is a really good programmer to help me.In short, he told me I should learn Javascript.

I started to move on to Javascript from Python and I started loving it.Then I found React.And it is crazy to say that my journey to React's ecosystem was started with React Native.When I started introduced myself with React Native, me as a backend developer
coming from Django, personally I really enjoyed and amazed how the data binding in React Native is easy.Believe it or not I code React Native for about 5 months without seeing this website. I felt so bad and ashmed every time I think about it.

Me as a self-thougth developer with no CS background, the way I started into these programming technologies is pretty simple, I just go to Youtube.So I learnt React Native though it's documentation and tons of tutorials from Youtube, I didn't really understand how react reacts.
But one thing suprises me, who previously worked with templates

everytimes I change something the UI just changes

Data binding is the general technique of binding the data from any possible source together and synchronizing it with the UI.Before we talk anything about React, let's start with the venilla way.

To sync our data with the UI, obviously we need to know if our data change somehow we first need to observe any changes in the data model.

One way data binding


class Binder {
    constructor(value) {
        this.observers = [];
        this.value = value;
    }
    notify() {
        this.observers.forEach(listener => listener(this.value));
    }
    listen(listener) {
        this.observers.push(listener);
    }
    get value() {
        return this.value;
    }
    set value(value) {
        if (val !== this.value) {
            this.value = value;
            this.notify();
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

In the above code, we have a simple Javascript class with some setters and getters.In the constructor we have an array of observers to detect
any possible data changing methods or events in our data model in our case the value and we have a setter calling our observers to take action on any changes.

    let myName = new Binder("Initial Name");
    let dataUpdater = (newName) => {
        // updater event to change the data model
        console.log('Your coming new Name is ', newName)
    };
    myName.listen(dataUpdater);
    myName.value = 'Arkar Kaung Myat';
Enter fullscreen mode Exit fullscreen mode

So are basically calling the notify function whenever we got an update in our data source through event listeners.That is how I understand one way data binding works.
Let's try with simple html doms.

    <div>
        <label for="Number">Enter Number</label><br>
        <input type="number" id="number" placeholder="Enter second Number">
    </div>

    <br>
    <p>Number : </p>
    <h1 id="result"></h1>
Enter fullscreen mode Exit fullscreen mode

let number = document.querySelector('#number');
let result = document.querySelector('#result');

class Binder {
    constructor(value) {
        this.observers = [];
        this.data = value;
    }
    notify() {
        this.observers.forEach(listener => listener(this.data));
    }
    listen(listener) {
        this.observers.push(listener);
    }
    get value() {
        return this.data;
    }
    set value(value) {
        if (value !== this.data) {
            this.data = value;
            this.notify();
        }
    }
}

let num = new Binder(number.value);

let observer = (value) => {
    result.innerText = value;
}

num.listen(observer);
number.addEventListener('input', (e) => {
    num.value = e.target.value;
});

Enter fullscreen mode Exit fullscreen mode

Well I think that's a bit self explanatory.

Binding data model with multiple data input

The above example is pretty easy to understand and I think that explains pretty well on how you can work around one way data binding.
So let's say we have multiple data input for our data model to rely on.Let say you want to update data input from two input form and update to the view.How do we create such a binding?


class WithEffect extends Binder {
    constructor(data,dependencies){
        super(data());
        const listener = () => {
            this.data = data();
            this.notify();
        };
    };

    get value() {
        return this.data;
    };

    set value(val) {
        // just to show you
        console.log(val, 'What do you expect ! is is read-only computed value');
        throw 'is is read-only computed value';
    }
}

Enter fullscreen mode Exit fullscreen mode

Lets see in action


const num1 = new Binder(100);
const num2 = new Binder(900);

let observer = () => {
    return Number(num1.value) + Number(num2.value)
}
const full = new WithEffect(observer, [num1, num2]);
console.log(full.value);

// try full.value = 40000

Enter fullscreen mode Exit fullscreen mode

Here is DOM in function


const num1 = new Binder(number1.value);
const num2 = new Binder(number2.value);

let observer = () => {
    result.innerText = `${Number(num1.value) + Number(num2.value)}`;
    return Number(num1.value) + Number(num2.value);
}

const full = new WithEffect(observer, [num1, num2]);

number1.addEventListener('input', () => {
    num1.value = number1.value;
});

number2.addEventListener('input', () => {
    num2.value = number2.value;
});

Enter fullscreen mode Exit fullscreen mode

So as I understand, updaing on the UI is based on the data model.But updating the data model is done explicitly
by some listener or observers through callbacks or events from some possible data source.In our case, the input.

Two ways data binding

In the case of two ways, whenever we update the data model, we need to update the UI.And also the other way around.
In case of chainging the UI we need to update the data model.

Two way data binding

    <div>
        <label for="number1">Enter Number1</label><br>
        <input onkeyup="update(event)" type="number" id="number1" placeholder="Enter second Number" data-binder="A">
    </div>
    <br>
    <div>
        <label for="number2">Enter Number2</label><br>
        <input onkeyup="update(event)" type="number" id="number2" placeholder="Enter first Number " data-binder="A">
    </div>
Enter fullscreen mode Exit fullscreen mode

We got observer for each of the input in the above example.

let binded_inputs = document.querySelectorAll('[data-binder="number"]');

function update(event) {
    for (var i in binded_inputs) {
        binded_inputs[i].value = event.currentTarget.value;
    }
}

Enter fullscreen mode Exit fullscreen mode

What about in React !

In React, it is never really designed for two way data binding even though it can be implement (Two Way Data Binding Helpers)(https://reactjs.org/docs/two-way-binding-helpers.html)

So lets take a look at some React code.

   const [message, setMessage] = useState('Hello World');
Enter fullscreen mode Exit fullscreen mode

So we got a data model or state for our view and we want to stay sync between our view and in this case our state.

function App() {
  const [message, setMessage] = useState('Hell`o World');

  let handleChange = (e) => {
    setMessage(e.target.value)
  }
  return (
    <div className="App">
      <input type="text" value={message} onChange={handleChange} />
      <br>
      <h1>{message}</h1>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Everytime we type in our input we are calling the callback handler to update our day model.
So react let us change the data model from the view or some data source but we cannot do it directly, but we can attach events or handlers
to the view to observe the changes and update the model.

Let's take a look at some React.

    let myApp = document.getElementById('root');
    ReactDOM.render(<h1>Welcome to React</h1>, myApp);
Enter fullscreen mode Exit fullscreen mode

Just basically rendering heading and lets put some data in it.

let myApp = document.getElementById('root');
let number = 0;

let handleClick = () => {
  number++;
  console.log(number)
};

let content = (
  <div>
    <h1>Welcome to React</h1>
    <p>Here is the number</p>
    <h1>{number}</h1>

    <br />
    <button onClick={handleClick}>ADD</button>
  </div>
)
ReactDOM.render(content, myApp);

Enter fullscreen mode Exit fullscreen mode

When you try this you can see in the console logging out the number but it is not updating the UI.
We got data source and some data to show how do we bind them together ?

So lets see try changing the code as below and you will see the diffreence

let myApp = document.getElementById('root');
let number = 0;

let handleClick = () => {
  number++;
  console.log(number)
  renderContent()
};

let renderContent = () => {
  let content = (
    <div>
      <h1>Welcome to React</h1>
      <p>Here is the number</p>
      <h1>{number}</h1>

      <br />
      <button onClick={handleClick}>ADD</button>
    </div>
  );
  ReactDOM.render(content, myApp);
};
renderContent()
Enter fullscreen mode Exit fullscreen mode

So what we do here is we put the content inside the renderContent funtion so basically
everytimes we click the button we are calling the renderContent function and creating a new updated instance of our content.
Click and inspect the our elements and you can see only the h1 is making the splash everytime we clicked throught the button.

Top comments (0)