npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-data-binder

v1.1.1

Published

Easily bind data into React Components via props.

Downloads

15

Readme

react-data-binder

Simple way to bind data into React Components via props.

TOC

Why?

Normally, when you are rending a React component. This is the usual process you do:

  • Start showing a loading screen.
  • Fetch data and wait.
  • Once data received, render those data

Then if something goes wrong, you need to show an error.

Additionally, if you create a subscription then you need to clean up those subscriptions when the component is dying.

So, you have to do a lot of stuff.


That's what we are going to fix with this project. You simply tell it how to get data and clean up resources. Then it'll do the hard work you. This is a universal project and work with any kind of data source, whether it's GraphQL, Meteor, Redux or Rx.js observable.

Installation

npm i --save react-data-binder

Basic Usage

Let's say we need to build a clock. First let's create a component to show the time.

const Time = ({time}) => (<div>Time is: {time}</div>);

Now let's define how to fetch data for this:

const onPropsChange = (props, onData) => {
  const handle = setInterval(() => {
    const time = (new Date()).toString();
    onData(null, {time});
  }, 1000);

  const cleanup = () => clearInteval(handle);
  return cleanup;
};

On the above function, we get data for every seconds and send it via onData. Additionally, we return a cleanup function from the function to cleanup it's resources.

Okay. Now it's time to create the clock:

import { bindData } from 'react-data-binder';
const Clock = bindData(onPropsChange)(Time);

That's it. Now render the clock to the DOM.

import ReactDOM from 'react-dom';
ReactDOM.render(<Clock />, document.body);

See this in live: https://jsbin.com/bejiqu/1/edit?js,output

Additional Benefits

Other than main benefits, now it's super easy to test our UI code. We can easily do it via a set of unit tests.

  • For that UI, simply test the plain react component. In this case, Time (You can use enzyme for that).
  • Then test onPropsChange for different scenarios.

Do this for all of your components. You can test your code pretty easily.

API

You can customize the higher order component created by bindData in few ways. Let's discuss.

Handling Errors

Rather than showing the data, something you need to deal with error. Here's how to use bindData for that:

const onPropsChange = (props, onData) => {
  // oops some error.
  onData(new Error('Oops'));
};

Then error will be rendered to the screen (in the place where component is rendered). You must provide a JavaScript error object.

You can clear it by passing a some data again like this:

const onPropsChange = (props, onData) => {
  // oops some error.
  onData(new Error('Oops'));

  setTimeout(() => {
    onData(null, {time: Date.now()});
  }, 5000);
};

Detect props changes

Some times can use the props to custom our data fetching logic. Here's how to do it.

const onPropsChange = (props, onData) => {
  const handle = setInterval(() => {
    const time = (props.timestamp)? Date.now() : (new Date()).toString();
    onData(null, {time});
  }, 1000);

  const cleanup = () => clearInteval(handle);
  return cleanup;
};

Here we are asking to make the Clock to display timestamp instead of a the Date string. See:

ReactDOM.render((
  <div>
    <Clock timestamp={true}/>
    <Clock />
  </div>
), document.body);

See this in live: https://jsbin.com/nohuqa/edit?js,output

Change the Loading Component

const MyLoading = () => (<div>Hmm...</div>);
const Clock = bindData(onPropsChange)(Time, MyLoading);

Change the Error Component

const MyError = ({error}) => (<div>Error: {error.message}</div>);
const Clock = bindData(onPropsChange)(Time, null, MyError);

Using with XXX

You can use react-bind-data with a huge range of projects. Let me show you couple of them:

Bind GraphQL queries via Lokka

const Time = ({time}) => (<div>Time is: {time}</div>);
const client = new Lokka({...});
const query = `
    {
        time: serverTime
    }
`;

const onPropsChange = (props, onData) => {
  return client.watchQuery(query);
};
const Clock = bindData(onPropsChange)(Time);

Check here to it in action: https://goo.gl/K1LhYk/

Using with Meteor

For that you need to use bindTrackerData method instead of bindData. Then you can watch any Reactive data inside that.

const Time = ({time}) => (<div>Time is: {time}</div>);
const onPropsChange = (props, onData) => {
  const handler = Meteor.subscribe('serverTime');
  if(hander.ready()) {
    const {time} = ServerTimeCollection.findOne();
    onData(null, {time});
  } else {
    onData(null, null);
  }
};

// Note the use of bindTrackerData
const Clock = bindTrackerData(onPropsChange)(Time);

Using with Rx.js Observables

var source = Rx.Observable.interval(1000);

const Time = ({time}) => (<div><b>Time is</b>: {time}</div>);

const onPropsChange = (props, onData) => {
  const sub = source.subscribe(() => {
    const time = new Date().toString();
    onData(null, {time})
  });
  return sub.completed.bind(sub);
};

const Clock = bindData(onPropsChange)(Time);

Try this live: https://jsbin.com/bofaxi/edit?js,output

Using with Redux


const defaultState = {time: new Date().toString()};
const store = Redux.createStore((state = defaultState, action) => {
  switch(action.type) {
    case 'UPDATE_TIME':
      return {
        ...state,
        time: action.time
      };
    default:
      return state;
  }
});

setInterval(() => {
  store.dispatch({
    type: 'UPDATE_TIME', 
    time: new Date().toString()
  });
}, 1000);

const Time = ({time}) => (<div><b>Time is</b>: {time}</div>);

const onPropsChange = (props, onData) => {
  return store.subscribe(() => {
    const {time} = store.getState();
    onData(null, {time})
  });
};

const Clock = bindData(onPropsChange)(Time);
                   
ReactDOM.render(<Clock />, document.getElementById('react'))

Try this live: https://jsbin.com/xazuzo/2/edit?html,js,output

Caveats

  • In the server, we won't be able to cleanup resources even if you return the cleanup function. That's because, there is no functionality called unmount in the server. So, make sure to handle the cleanup logic by yourself in the server.