Skip to content

subbu963/grape

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GrapeJS

It's a React-ish library for building UI's. It uses virtual dom underneath and follows somewhat similar api. I started this initially cause I was fascinated by virtual dom and wanted to learn and experiment with it.

Features

  • Lightweight(~7.6 KB gzipped and minified)
  • Server side rendering
  • Conditional class attributes

Installation

$ yarn add https://github.com/subbu963/grape
$ yarn add https://github.com/subbu963/babel-preset-grape --dev

We need to add babel-preset-grape to .babelrc

{
    "presets": [
        "babel-preset-grape"
    ]
}

Basics

Components

Components can implement their own render method. Without which it will render a empty component.

GrapeJS supports writing html and css attributes with their actual name unlike React. We can just use class instead of className, 'onclick' instead of onClick, etc

import grape, {Component} from 'grape';

class Hello extends Component {
    onHelloClick() {}
    render() {
        return (
            <div class="hello" onclick={this.onHelloClick.bind(this)}>Hello World!</div>
        );
    }
}

You can get the props from this.props, state from this.state and children from this.children.

You can use a list of JSX nodes similar to React. We need to pass a unique key for every child component.

import grape, {Component} from 'grape';

class List extends Component {
    render() {
        return (
            <ul>{this.props.items.map(item => <li key={item.id}>{item.text}</li>)}</ul>
        );
    }
}

You can add styles using objects and conditional classes using arrays without the need for libraries like classnames.

import grape, {Component} from 'grape';

class List extends Component {
    render() {
        const style = {
            color: this.state.counter % 2 ? 'red': 'blue',
            'background-color': '#FFF'
        };
        const classes = [this.state.counter % 2 && 'odd', 'default-class']
        return (
            <div style={style} class={classes}>
        );
    }
}

Components can set state using this.setState

import grape, {Component} from 'grape';

class Button extends Component {
    constructor(...args) {
        super(...args);
        this.state = {
            color: 'red'
        };
    }
    toggleColor() {
        this.setState({
            color: this.state.color === 'red' ? 'blue': 'red'
        });
    }
    render() {
        return (
            <button style={{'background-color':this.state.color}} onclick={this.toggleColor.bind(this)}>Click me</button>
        );
    }
}

GrapeJS only has two lifecycle hooks - mounted for when the component is mounted and willUnmount for when component is going to be removed from dom.

import grape, {Component} from 'grape';

class Counter extends Component {
    constructor(...args) {
        super(...args);
        this.state = {
            counter: 0
        };
    }
    mounted() {
        this.interval = window.setInterval(() => this.setState({
            counter: this.state.counter + 1
        }));
    }
    willUnmount() {
        window.clearInterval(this.interval);
    }
    render() {
        return (
            <p>{this.state.counter}</p>
        );
    }
}

Server side rendering:

import {renderToString} from 'grape/lib/dom/server';
import grape from 'grape';
import App from '../client/components/app';

const html = renderToString(<App/>, true);

Planned Features

  • Explore moving the diffing algorithm to workers or webassembly
  • Implement functional components
  • Make updates async

Stats

Currently the library weighs around ~ 7.6 KB gzipped and minified compared to React which ~ 49.8 KB. GrapeJS has a lot less features and is still in early stages. We should able to squeeze the size lot more by removing a lot of ES6 code that is used without compromising on performance.

Releases

No releases published

Packages

No packages published