- Notifications
You must be signed in to change notification settings - Fork0
Easy to do one-way & two-way data binding in React & Native
License
melthaw/react-databinding
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
As we know ,the two-way binding is general feature inAngular &Vue.jsbut not supported inReact.So we have to write down much code to handle the technical issue not focus on the business,react-databinding
is used to make it easier.
- Easy to understand and simple to use
- Two level designed APIs
- Top level for Component#render() (one-way & two-way binding)
- Lower level for functional programming ( Functor & Monad )
- The value can be evaluated by path expression
- Easy to customize the behaviour if the target component is changed
> npm install react-databinding --save
There are two styles to do data binding inreact-databinding
.
style | import |
---|---|
by manual | import {oneWayBind, twoWayBind} from 'react-databinding/react-data-bind' |
with decorator | import {oneWayBind, twoWayBind} from 'react-databinding/react-decorator' |
Here we show the different between the two styles of data binding ,we choose one-way binding for example , the two-way binding is similar .
import{oneWayBind,twoWayBind}from'react-databinding/react-data-bind';//by manualclassSampleComponentextendsReact.Component{render(){let$=oneWayBind(this.props);return(<div><h1>{$('data.title')}</h1></div>)}}
import{oneWayBind,twoWayBind}from'react-databinding/react-decorator';//with decoratorclassSampleComponentextendsReact.Component{@oneWayBind()render($){return(<div><h1>{$('data.title')}</h1></div>)}}
If you choose the style of decorator, remember pass the binding operation ($
in our example) to the render function.
There are many solutions to implement one-way or two-way binding in React world ,but we like more simple and less coding API if we use it in therender()
function.
Here we will show how to get the easiest to understand and simplest to use one-way and two-way data binding in React Component.
First, let's prepare the container Component to create a component and pass something as props to it.
constdata={title:'hello world',body:'blablablabla...'}constContainerComponent=()=>(<ImmutableComponentdata={data}/>)
Then goes to theImmutableComponent
which we will show the one-way binding
import{React}from'react';import{oneWayBind}from'react-databinding';classImmutableComponentextendsReact.Component{render(){// $ is curried function and please feel free to rename it in your project.let$=oneWayBind(this.props);// 'hello world' will be shown as the h1 titlereturn(<div><h1>{$('data.title')}</h1></div>);}}
Nothing special, just one more line to create a curried$
function which will do the left work in the JSX part.
As you see, it's quite simple to do one-way binding ,the magic is$
function , it accept the path ('data.title'
) and evaluate based on the Component's props.
One more thing, the$
function can accept a default value or a lambda callbackwhich will be very useful if you want to handle the null eval result.
consttodolist=[{title:'complete the readme before this weekend',tags:['help','doc'],status:'pending'}];
Show'unknown'
if the author not defined in todo
$('todolist.0.author','unknown')
Show comma-joined tags
$('todolist.0.tags',v=>v ?v.join(','):'unknown')
As you see, complex path is supported, the array index is taken as the key of object , please feel free to try it out.
The two-way binding is a bit different but similar. Here we use$$
to indicate it's a two-way binding.
First, let's prepare the container Component to create a component and pass something as props to it.
constdata={username:'react-databinding',nickname:'two-way binding'}constContainerComponent=()=>(<MutableComponentuser={data}/>)
Then goes to theMutableComponent
which we will show the two-way binding.
classMutableComponentextendsReact.Component{constructor(props,context){super(props,context);let{ user}=props;this.state={user};}render(){let$$=twoWayBind(this);return(<div><inputid="username"type="text"{...$$('user.username')}/><inputid="nickname"type="text"{...$$('user.password')}/></div>);}}
In therender()
function , the$$
returns a composed object, so we use the...
to expand as the input's props.
Of course, the importantimmutable-js is supported.
We try to keep the general API and immutable supported API in the same , the only different is the import part.
//generalimport{oneWayBind,twoWayBind}from'react-databinding';//immutableimport{oneWayBind,twoWayBind}from'react-databinding/immutable';//decoratorimport{oneWayBind,twoWayBind}from'react-databinding/immutable/react-decorator';
But how it works , what is working on the backend. Let's show more example to explain it.
First, import thereact-databinding
import{F}from'react-databinding';
Now let's prepare the data to show the usage
constdata=[{calories:{total:0,fat:0},vitamins:{a:{total:0,retinol:0},b6:0,c:0},fats:{total:0},minerals:{calcium:0}},{calories:{total:150,fat:40},vitamins:{a:{total:100},b6:30,c:200},fats:{total:3}},{calories:{total:100,fat:60},vitamins:{a:{total:120,retinol:10},b6:0,c:200},minerals:{calcium:20}}];
case 1: iterate the data and get the value
before
letitem=data[1];if(item!=null){letfats=item.fats;if(fats!=null){lettotal=fats.total;//3}}
after
import{F,Optional}from'react-databinding';F.of(data).at('1.fats.total').value();//3//or(newOptional(data)).at('1.fats.total').value();//3
case 2: convert the data
before
letitem=data[1];if(item!=null){letfats=item.fats;if(fats!=null){lettotal=fats.total;if(total!=null){total=total+1;//4}}}
after
import{F,Optional}from'react-databinding';F.of(data).at('1.fats.total').map(v->v+1).value();//4//or(newOptional(data)).at('1.fats.total').map(v->v+1).value();//4
Yes , immutable is supported as well.The APIs is designed exactly matched as previous, the different is import part.
import{F}from'react-databinding/immutable';
And make sure the args you passed to F.of is an immutable object.
import{fromJS}from'immutable';import{F}from'react-databinding/immutable';letimmutableData=fromJS(data);F.of(immutableData).at('1.fats.total').map(v->v+1).value();//4
About
Easy to do one-way & two-way data binding in React & Native