Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
Ilima

onDragEnd Update React State

Recommended Posts

I'm not a React guy, but it looks like you've got some other issues in your code: 

Uncaught Error: Cannot remove node 3 because no matching node was found in the Store.
 

But the problem in your onDragEnd() method is scope - "this" refers to the Draggable instance, but you're calling this.toggleMode(this.x); and there is no such thing as "toggleMode()" on the Draggable instance. You can correct this by storing it as a variable outside that function like:

var toggleMode = this.toggleMode;

Draggable.create(... {
  onDragEnd() {
    toggleMode(this.x);
  }
});

Does that help?

  • Like 1
Link to post
Share on other sites
17 minutes ago, GreenSock said:

I'm not a React guy, but it looks like you've got some other issues in your code: 

Uncaught Error: Cannot remove node 3 because no matching node was found in the Store.
 

But the problem in your onDragEnd() method is scope - "this" refers to the Draggable instance, but you're calling this.toggleMode(this.x); and there is no such thing as "toggleMode()" on the Draggable instance. You can correct this by storing it as a variable outside that function like:


var toggleMode = this.toggleMode();

Draggable.create(... {
  onDragEnd() {
    toggleMode(this.x);
  }
});

Does that help?

Unfortunately didn't do anything, same problem 

 

Here is the demo with those changes https://codesandbox.io/s/funny-haslett-jj95u?file=/src/Box.jsx

Link to post
Share on other sites

Sorry, I accidentally had "()" after toggleMode. You're saving a reference to the function, not what it returns. 

var toggleMode = this.toggleMode;

But things aren't working because you've got other problems in your React code like I said. Open the console and you'll see the error messages. 

Quote

frontend.js:10187 Uncaught Error: Cannot add node 1 because a node with that id is already in the Store.

 

  • Like 2
Link to post
Share on other sites
1 hour ago, GreenSock said:

Sorry, I accidentally had "()" after toggleMode. You're saving a reference to the function, not what it returns. 


var toggleMode = this.toggleMode;

But things aren't working because you've got other problems in your React code like I said. Open the console and you'll see the error messages. 

 

It's weird... I have the similar Draggable with onDrag function which passes this as instance of react function. Here is the Demo Example on that: https://codesandbox.io/s/cool-forest-ddzft?file=/src/drag.js

 

For now I made the function work within the ComponentDidMount, and it worked: https://codesandbox.io/s/funny-haslett-jj95u?file=/src/Box.jsx 

But this is not the approach that would be good later. Is there a better way to find the Box and update the State? Or even move the Box based on State, the data will be based on db, where the box could be on the Second Grid or Third. (it's a similar logic like radio buttons, but instead of clicking on radio button we wanted to be able to move the button between options)

Link to post
Share on other sites

Using Jack's suggestion works fine:

componentDidMount() {
  var gridWidth = 120;
  var gridHeight = 60;

  const toggleMode = this.toggleMode;

  this.mode = Draggable.create(".box", {
    type: "x",
    dragClickables: true,
    edgeResistance: 0.65,
    bounds: ".mode_container_inner",
    lockAxis: true,
    inertia: true,
    liveSnap: true,
    onDragEnd() {
      toggleMode(this.x);
    },
    snap: {
      x: function (endValue) {
        return Math.round(endValue / gridWidth) * gridWidth;
      },
      y: function (endValue) {
        return Math.round(endValue / gridHeight) * gridHeight;
      }
    }
  });
}

Is that approach acceptable?

 

Also don't use regular selectors in your React code: ".box"".mode_container_inner", even if the DOM representation of your component is stable and doesn't change, is still a good idea to use refs for that. Also if a React purist sees that is going to have a stroke:

 

giphy.gif

 

Happy Tweening!!!

  • Like 4
Link to post
Share on other sites
On 9/18/2020 at 5:47 PM, Rodrigo said:

Using Jack's suggestion works fine:


componentDidMount() {
  var gridWidth = 120;
  var gridHeight = 60;

  const toggleMode = this.toggleMode;

  this.mode = Draggable.create(".box", {
    type: "x",
    dragClickables: true,
    edgeResistance: 0.65,
    bounds: ".mode_container_inner",
    lockAxis: true,
    inertia: true,
    liveSnap: true,
    onDragEnd() {
      toggleMode(this.x);
    },
    snap: {
      x: function (endValue) {
        return Math.round(endValue / gridWidth) * gridWidth;
      },
      y: function (endValue) {
        return Math.round(endValue / gridHeight) * gridHeight;
      }
    }
  });
}

Is that approach acceptable?

 

 

Yup 👍🏻 it worked! Thank you so much ☺️ 

Now I just need to figure out how to put the box on the second or third options based on database. Do you know any way to do that?

 

 

Link to post
Share on other sites
3 hours ago, Rodrigo said:

I took the liberty to transform your sample to a functional component if you ever end up wandering React's HooksLand :D

 

https://codesandbox.io/s/gsap-draggable-react-zfiun

 

Happy Tweening!!!

Thank you on that! I use React Hooks as well, but my team is still using React Components 😅

Probably it will take some time for us to change everything to hooks  🤔

Link to post
Share on other sites
1 hour ago, Ilima said:

Now I just need to figure out how to put the box on the second or third options based on database. Do you know any way to do that?

There are quite a few ways to do that, depending on the database, endpoints and if you're using an ORM and which of course. If you're DB is firebase then use async/await, if you're using Apollo with GraphQL then you have to use the Apollo client for components, if you're using an express backend with mongo, then axios or fetch would be the best approach, if you're using postgre SQL, then perhaps Prisma with GraphQL or Sequelize.

 

But the approach is basically get the data, update the component state and render the component based on the state properties. As I mentioned above, it all starts with the componentDidMount method. This sample asumes that you have an endpoint that returns an array of elements in JSON format:

import React, { Component } from "react";
import axios from "axios";

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      elements: [],
    };
  }
  
  componentDidMount() {
    axios.get("https://my-api.com/users")
      .then((response) => {
        this.setState({
          // axios returns any data passed by the endpoint in a data property
          elements: response.data
        });
      })
      .catch((e) => console.error(e))
  }
  
  render() {
    return (
      <div>
        {state.elements.map((element) => (<div key={element.id}>{element.name}</div>)}
      </div>
    );
  }
}

Happy Tweening!!!

  • Like 2
Link to post
Share on other sites
21 hours ago, Rodrigo said:

But the approach is basically get the data, update the component state and render the component based on the state properties. As I mentioned above, it all starts with the componentDidMount method. This sample asumes that you have an endpoint that returns an array of elements in JSON format:

 

Thanks 😊 I think I figured it out. What I wanted to do is basically if state says "second" then move the box to the second option: https://codesandbox.io/s/gsap-draggable-react-hooks-4ez0l?file=/src/Box.jsx 

 

Thank you Team Green for the reactive help!

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×