Writing JS posts with JBake : React JS

Intro

In this second entry about adding JS programming entries to JBake posts I’ve included a typical React TODO item example

The JS example I’m using here is just a quick draft just to show how to include JS and CSS code in a post entry. Don’t take it too seriosly.

Add required resources

To be able to work with react, and load the example script, I need to add the scripts attribute in the post header:

:scripts: https://unpkg.com/react@16/umd/react.development.js|https://unpkg.com/react-dom@16/umd/react-dom.development.js|js/2018/11/react.js

Basically, I’ve included the react, react-dom libraries at the header of the document, and then the example dependency inside the blog project’s assets js/2018/11/react.js . If I would like to add a custom css, you can add as well a css entry in the post header:

:css: css/2018/11/react.css

No JSX when using plain JS

Because JSX can’t be included through a `<script/>' import, I had to create a helper function to create new elements.

helper
const e = React.createElement;

TodoPanel

TodoPanel
class TodoPanel extends React.Component {
    constructor(props) { (1)
        super(props);
        this.state = {
            task: '',
            tasks: []
        };
    }

    handleChange (e) { (2)
        this.setState({task: e.target.value})
    }

    addItem () { (3)
        this.setState({
            tasks: [...this.state.tasks, this.state.task],
            task: ''
        })
    }

    deleteItem (item) { (4)
        this.setState({tasks: this.state.tasks.filter(x => x !== item)})
    }

    render() {  (5)
        return e('div', {id: 'todo'},
                 e('input', {type: 'text', onChange: (ev) => this.handleChange(ev), value: this.state.task}),
                 e('button', {onClick: () => this.addItem() }, 'Add'),
                 e(TodoItems, {tasks: this.state.tasks, delete: (item) => this.deleteItem(item)})
        );
    }
}
1 Create default state
2 Sets which is the current item to add
3 Adds the current item to the tasks list
4 Deletes the clicked item from the tasks list
5 renders the tasks panel

Creating items

The TodoItems component represents the tasks list. It only renders an ul elements containing as many items as tasks found in the task list.

TodoItems
class TodoItems extends React.Component {
    createTask (item) {
        return e(TodoItem, {key: item, delete: this.props.delete, item: item}, null)
    }

    render () {
        return e('ul', {key: 'items', className: 'items'}, this.props.tasks.map(x => this.createTask(x)))
    }
}

Every item of the task list is built using the TodoItem component

TodoItem
class TodoItem extends React.Component {
    render () {
        const { item } = this.props
        const itemSpan = e('p', {key: `item-p-${item}`}, item)
        const deleteButton = e('button',
                               {value: 'delete', key: `item-delete-${item}`, onClick: () => this.props.delete(item)},
                               'Delete')

        return e('li', {key: item},
                 e('span', {className: 'item'}, [itemSpan, deleteButton]))
    }
}

Render example

Finally, in order to render the TodoPanel in this document we need to link the component with an available dom element.

Render
const domContainer = document.querySelector('#like_button_container');
ReactDOM.render(e(TodoPanel), domContainer);

Result

It seems easy to add simple vanilla JS examples to a post. However trying to create more complex examples would require a proper build tool such as plain npm scripts or webpack.

Resources