Skip to content

React on ES6 without mixins #713

Closed
Closed

Description

@kbiedrzycki

Hello,

I wanted to integrate Sortable module with our code, but the problem is that we are using ES6 in our code.. As far as I know, mixins cannot be used in this situation, but they can be switched to Composed Components. Maybe there is anyone who already tried to convert that?

Activity

  1. kbiedrzycki commented on Jan 7, 2016

    @kbiedrzycki
    Author

    Okay I've played around the mixin and created High Order Component from that and it works, but, wondering, maybe someone know how to get the internal instance of HOC in proper way, cause now I'm getting the instance of that component by accessing this._reactInternalInstance._renderedComponent._instance

  2. kbiedrzycki commented on Jan 8, 2016

    @kbiedrzycki
    Author

    Okay, figured it out. In HOC when I am passing ComposedComponent, in render method I am just adding ref attribute, and then when I want to get that instance I am just calling this.refs.[refName]. If someone would like to take a look at HOC version instead of mixin just reply here, I'll try to make a merge request then.

  3. cheton commented on Jan 27, 2016

    @cheton

    I managed to get it working by rewriting existing react-sortable-mixin.js in ES6. See my example below:

    react-sortable.jsx

    import _ from 'lodash';
    import React from 'react';
    import ReactDOM from 'react-dom';
    import Sortable from 'sortablejs';
    
    const defaultOptions = {
        ref: 'list',
        model: 'items',
        onStart: 'handleStart',
        onEnd: 'handleEnd',
        onAdd: 'handleAdd',
        onUpdate: 'handleUpdate',
        onRemove: 'handleRemove',
        onSort: 'handleSort',
        onFilter: 'handleFilter',
        onMove: 'handleMove'
    };
    
    let _nextSibling = null;
    let _activeComponent = null;
    
    const getModelName = (component) => {
        let { sortableOptions = {} } = component;
        let { model } = sortableOptions;
        return model || defaultOptions.model;
    };
    
    const getModelItems = (component) => {
        let model = getModelName(component);
        let { state = {}, props = {} } = component;
        let items = state[model] || props[model] || [];
        return items.slice();
    };
    
    class ReactSortable extends React.Component {
        _sortableInstance = null;
    
        componentDidMount() {
            const options = _.merge({}, defaultOptions, this.sortableOptions);
            const emitEvent = (type, evt) => {
                const method = this[options[type]];
                method && method.call(this, evt, this._sortableInstance);
            };
            let copyOptions = _.extend({}, options);
    
            [ // Bind callbacks so that 'this' refers to the component
                'onStart', 'onEnd', 'onAdd', 'onSort', 'onUpdate', 'onRemove', 'onFilter', 'onMove'
            ].forEach((name) => {
                copyOptions[name] = (evt) => {
                    if (name === 'onStart') {
                        _nextSibling = evt.item.nextElementSibling;
                        _activeComponent = this;
                    } else if (name === 'onAdd' || name === 'onUpdate') {
                        evt.from.insertBefore(evt.item, _nextSibling);
    
                        let newState = {};
                        let remoteState = {};
                        let oldIndex = evt.oldIndex;
                        let newIndex = evt.newIndex;
                        let items = getModelItems(this);
    
                        if (name === 'onAdd') {
                            let remoteItems = getModelItems(_activeComponent);
                            let item = remoteItems.splice(oldIndex, 1)[0];
                            items.splice(newIndex, 0, item);
    
                            remoteState[getModelName(_activeComponent)] = remoteItems;
                        } else {
                            items.splice(newIndex, 0, items.splice(oldIndex, 1)[0]);
                        }
    
                        newState[getModelName(this)] = items;
    
                        if (copyOptions.stateHandler) {
                            this[copyOptions.stateHandler](newState);
                        } else {
                            this.setState(newState);
                        }
    
                        (this !== _activeComponent) && _activeComponent.setState(remoteState);
                    }
    
                    setTimeout(() => {
                        emitEvent(name, evt);
                    }, 0);
                };
    
            });
    
            let domNode = ReactDOM.findDOMNode(this.refs[options.ref] || this);
            this._sortableInstance = Sortable.create(domNode, copyOptions);
        }
        componentWillReceiveProps(nextProps) {
            let newState = {};
            let model = getModelName(this);
            let items = nextProps[model];
    
            if (items) {
                newState[model] = items;
                this.setState(newState);
            }
        }
        componentWillUnmount() {
            this._sortableInstance.destroy();
            this._sortableInstance = null;
        }
    }
    
    export default ReactSortable;

    Sample code:

    import ReactSortable from './ReactSortable';
    
    class SortableContainer1 extends ReactSortable {
        state = {
            items: [0, 1, 2, 3, 4]
        };
        sortableOptions = {
            group: 'shared'
        };
    
        render() {
            let items = this.state.items.map((text, index) => {
                return <li key={index}>{text}</li>;
            });
    
            return (
                <div>
                    <ul ref="list">{items}</ul>
                </div>
            );
        }
    }
    
    class SortableContainer2 extends ReactSortable {
        state = {
            items: [5, 6, 7, 8, 9]
        };
        sortableOptions = {
            group: 'shared'
        };
    
        render() {
            let items = this.state.items.map((text, index) => {
                return <li key={index}>{text}</li>;
            });
    
            return (
                <div>
                    <ul ref="list">{items}</ul>
                </div>
            );
        }
    }
  4. cheton commented on Jan 28, 2016

    @cheton

    @falzhobel Yes! It's basically the same but only to adopt changes for React v0.14 (e.g. ReactDOM).
    It would be great if a ES6 version of react-sortable.jsx is available for developers to import to their projects. For example:

    import ReactSortable from 'sortablejs/react-sortable';
  5. cheton commented on Mar 10, 2016

    @cheton

    A higher order React component (HOC) for Sortable is available at https://github.com/cheton/react-sortable.

    You can run npm install --save react-sortablejs to install the package.

  6. RubaXa commented on Jul 4, 2016

    @RubaXa
    Collaborator

    Dear all! Meteor is moved to the separate repository. If this issue is still actual, please create it there once again and this rojects needs a maintainer:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions