Features

Key features that make up the main value proposition for Lore

Filtering

Useful for viewing a subset of data that matches a specific criteria.

Visualization

This video demonstrates what filtering looks like. Screenshots are from the Simply Social prototype that Invision provides you when you sign up for an account.

Usage

Let's say you have an API with a /posts endpoint, and you want to retrieve a list of Posts created by the Author whose id is 123. To do that, pass a where clause to the connect call like this:

@connect(function(getState, props) {
  return {
    posts: getState('post.find', {
      where: {
        authorId: '123'
      }
    })
  };
})

Assuming your API server is located at http://api.example.com, this call will get transformed into the following network request:

http://api.example.com/posts?authorId=123

Lore's default behavior is to convert the where clause into a query string. So if you passed in a second property to the where clause, like this:

where: {
  authorId: '123',
  title: 'Bacon'
}

It would get converted into this network request:

http://api.example.com/posts?authorId=123&title=Bacon

Since it will take time for the network request to complete, let's focus on the component next. The component is going to receive a prop named posts containing the result of our request for data.

@connect(function(getState, props) {
  return {
    posts: getState('post.find', {
      where: {
        authorId: '123'
      }
    })
  };
})
class Component extends React.Component {

  static propTypes = {
    posts: React.PropTypes.object.isRequired
  };

  render() {
    var posts = this.props.posts;

    // todo: render the posts
  }
};

Since our network request was just sent out, we won't have any data yet. So posts will look like this:

posts = {
  state: 'FETCHING',
  data: [],
  query: { where: { authorId: '123' } }
}

We don't have any data to render yet, but the query field is a stringified JSON that tells us what data we asked for, and the state field tells us that data is being fetched. So let's render a loading message while we're waiting for the data to return from the API server.

@connect(function(getState, props) {
  return {
    posts: getState('post.find', {
      where: {
        authorId: props.params.authorId
      }
    })
  };
})
class Component extends React.Component {

  static propTypes = {
    posts: React.PropTypes.object.isRequired
  };

  render() {
    var posts = this.props.posts;

    if (posts.state === PayloadStates.FETCHING) {
      return (
        <div>Loading posts...</div>
      );
    }

    // todo: render posts
  }
};

After a time our network request will come back, the Redux store will be updated, and our component will be rerendered. But this time we'll actually have data, so our posts will look like this:

posts = {
  state: 'RESOLVED',
  data: [
    {
      id: '1',
      cid: 'c1',
      state: 'RESOLVED',
      data: {
        title: 'Bacon is yummy',
        authorId: '123'
      }
    },
    {
      id: '2',
      cid: 'c1',
      state: 'RESOLVED',
      data: {
        title: 'An ode to Bacon',
        authorId: '123'
      }
    }
  ],
  query: { where: { authorId: '123' } }
}

The state value of RESOLVED let's you know that nothing is happening; the request has been resolved. And now, ourdata property contains an array of Posts. So let's render that array to display the lists of posts by that author:

connect(function(getState, props) {
    return {
      posts: getState('post.find', {
        where: {
          authorId: props.params.authorId
        }
      })
    };
  })(
  createReactClass({

    propTypes: {
      posts: React.PropTypes.object.isRequired
    },

    render: function() {
      var posts = this.props.posts;

      if (posts.state === PayloadStates.FETCHING) {
        return (
          <div>Loading posts...</div>
        );
      }

      return (
        <ul>
          {posts.data.map((post) => {
            return (
              <li key={post.id || post.cid}>
                {post.data.title}
              </li>
            );
          })}
        </ul>
      );
    }
  })
);

Example Code

Example code showing how to filter data.

connect(function(getState, props) {
    return {
      posts: getState('post.find', {
        where: {
          authorId: props.params.authorId
        }
      })
    };
  })(
  createReactClass({

    propTypes: {
      posts: React.PropTypes.object.isRequired
    },

    renderPost: function(post) {
      return (
        <li key={post.id || post.cid}>
          {post.data.title}
        </li>
      );
    },

    render: function() {
      var posts = this.props.posts;

      if (posts.state === PayloadStates.FETCHING) {
        return (
          <div>Loading posts...</div>
        );
      }

      return (
        <ul>
          {posts.data.map(this.renderPost)}
        </ul>
      );
    }
  })
);
class Component extends React.Component {

  constructor(props) {
    super(props);
    this.renderPost = this.renderPost.bind(this);
  }

  renderPost(post) {
    return (
      <li key={post.id || post.cid}>
        {post.data.title}
      </li>
    );
  }

  render() {
    var posts = this.props.posts;

    if (posts.state === PayloadStates.FETCHING) {
      return (
        <div>Loading posts...</div>
      );
    }

    return (
      <ul>
        {posts.data.map(this.renderPost)}
      </ul>
    );
  }
};

Component.PropTypes = {
  posts: React.PropTypes.object.isRequired
};

export default connect(function(getState, props) {
  return {
    posts: getState('post.find', {
      where: {
        authorId: props.params.authorId
      }
    })
  };
})(Component);
@connect(function(getState, props) {
  return {
    posts: getState('post.find', {
      where: {
        authorId: props.params.authorId
      }
    })
  };
})
class Component extends React.Component {

  static propTypes = {
    posts: React.PropTypes.object.isRequired
  };

  constructor(props) {
    super(props);
    this.renderPost = this.renderPost.bind(this);
  }

  renderPost(post) {
    return (
      <li key={post.id || post.cid}>
        {post.data.title}
      </li>
    );
  }

  render() {
    var posts = this.props.posts;

    if (posts.state === PayloadStates.FETCHING) {
      return (
        <div>Loading posts...</div>
      );
    }

    return (
      <ul>
        {posts.data.map(this.renderPost)}
      </ul>
    );
  }
};