Fork me on GitHub
#reagent
<
2017-06-06
>
reefersleep06:06:17

I figured it out. Think I'll add an updated example to the reagent cookbook.

osmirnov12:06:07

Have a problem with component update, when atom state changed, have some child in component-will-update, but when atom changed i receive TypeError: Cannot read property 'set' of undefined and similar...

pesterhazy12:06:10

That's not enough information to guess the cause

pesterhazy12:06:32

Can you post your code?

osmirnov12:06:42

Component re-render successful when atom changed, but it didn't apply property for new :dataSource.

pesterhazy13:06:54

still not enough context to see the issue I'm afraid

pesterhazy13:06:10

check this as an example for including foreign js in a reagent component: https://github.com/reagent-project/reagent-cookbook/tree/master/recipes/google-maps

pesterhazy13:06:53

oh, also think about when component-will-update fires

pesterhazy13:06:32

that's only if props change, or component state changes, or the ratom triggers a force update

pesterhazy13:06:56

what I'd do is build an inner component that takes the data as a prop

pesterhazy13:06:24

then have an outer component

(defn outer [] [inner @state])

pesterhazy13:06:54

in the lifecycle methods you'll have access to the new state in the props

pesterhazy13:06:27

that gives you a clean separation of the reagent-controlled outer component (which derefs the ratom), and the stateful, sideffectful inner component

kennethkalmer20:06:49

hi folks, I need some help with figuring out how to mimic this snippet in hiccup/reagent

kennethkalmer20:06:16

I’ve lost track of all the incantations I’ve tried

gadfly36120:06:02

# Step 1 Add the following to project.clj

[cljsjs/react-sticky "5.0.8-0"]
# Step 2 Require react-sticky in your ns
(ns foo.core
  (:require
   [cljsjs.react-sticky]))
# Step 3 Create reagent versions of the sticky components
(def sticky-container (reagent/adapt-react-class (aget js/ReactSticky "StickyContainer")))
(def sticky (reagent/adapt-react-class (aget js/ReactSticky "Sticky")))
# Step 4 Use reagent components as you'd expect
[sticky-container
  [sticky ... ]]

kennethkalmer20:06:39

yeah, but the syntax changed in 6.0.1 and I’m trying to get it working before sending a cljsjs PR for the update

kennethkalmer20:06:30

I’m using 5.0.8 atm, wanna bump to 6.0.1 to see if these annoying prop-type warnings go away 🙂

escherize20:06:45

woah that is awesome

juhoteperi20:06:35

As I minor note, I'd replace aget with just property access: (reagent/adapt-react-class js/ReactSticky.StickyContainer), aget is meant just for arrays

gadfly36120:06:58

@kennethkalmer ah sorry, i missed the intent of your question 😁

kennethkalmer20:06:09

no sweat, awesome reply still!

kennethkalmer20:06:38

that would definitely help others, so never stop doing that 😄

kennethkalmer20:06:03

I just can’t figure out this piece:

<Sticky>
            {
              ({ isSticky, wasSticky, style, distanceFromTop, distanceFromBottom, calculatedHeight }) => {
                console.log({ isSticky, wasSticky, style, distanceFromTop, distanceFromBottom, calculatedHeight });
                return <Header style={style} />
              }
            }
          </Sticky>

juhoteperi20:06:58

Hmm, lambda function using JS object destructuring maybe?

juhoteperi20:06:08

But what is calling the function in JSX

kennethkalmer20:06:42

I either get react-sticky complaining that the child is not a function, or react blowing up with an undefined somewhere

juhoteperi20:06:23

Oh, the Sticky children must be a function... not sure if that works with Reagent

rgdelato20:06:26

Sticky expects it's React children to be a function. The function takes a single map argument with the keys isSticky, wasSticky, etc.

rgdelato20:06:03

I'd assume you could do [my-component {:props ,,,} (fn [] ,,,)]? ...does that not work?

kennethkalmer20:06:22

tried it, didn’t work

juhoteperi20:06:32

the parameter is not a map, but JS object

rgdelato20:06:16

maybe [my-component {:children (fn [] ,,,)}]?

kennethkalmer20:06:27

same exception: Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it’s defined in. Check the render method of Sticky.

juhoteperi20:06:58

Does the exception say if it is from Reagent or React?

kennethkalmer20:06:19

react-dom.inc.js:17896 Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in. Check the render method of `Sticky`.
    at invariant (react-dom.inc.js:17896)
    at instantiateReactComponent (react-dom.inc.js:16037)
    at instantiateChild (react-dom.inc.js:4267)
    at react-dom.inc.js:4294
    at traverseAllChildrenImpl (react-dom.inc.js:16549)
    at traverseAllChildrenImpl (react-dom.inc.js:16565)
    at traverseAllChildren (react-dom.inc.js:16644)
    at Object.instantiateChildren (react-dom.inc.js:4293)
    at ReactDOMComponent._reconcilerInstantiateChildren (react-dom.inc.js:10378)
    at ReactDOMComponent.mountChildren (react-dom.inc.js:10417)

kennethkalmer20:06:30

apologies, should have pasted the whole thing

kennethkalmer20:06:02

it is the same wether :children (fn [] ...) or as the only child in the hiccup vector

juhoteperi20:06:15

React JSX format probably does some magic for the functions

kennethkalmer20:06:07

is it worth opening an issue on reagent if this isn’t supported?

juhoteperi20:06:14

Obviously passing functions as parameters to native Cljs components works fine

kennethkalmer20:06:31

i’m considering dropping the component, but I fear others might go down this rabbit hole too… since it is on cljsjs, and I’ve done the work to issue a PR for 6.0.1

juhoteperi21:06:30

Did you add console.log or such to the function, what if the function is called okay but the return value doesn't work?

juhoteperi21:06:28

return <Header style={style} /> in the example would be compiled to proper React call, but if you just return [Header] in Reagent it is just a cljs vector

kennethkalmer21:06:58

just added a log, it got called

juhoteperi21:06:33

Try wrapping the return value to reagent.core/as-element

kennethkalmer21:06:54

OMG, used as-component and it worked, testing as-element

juhoteperi21:06:19

they are the same, as-component is just deprecated name

juhoteperi21:06:40

Hah, that took some thinking to understand

kennethkalmer21:06:01

magic, I’m still not sure I understand it (yet)

kennethkalmer21:06:33

but I’ll let it simmer and update the cljsjs/react-sticky readme with a proper example

juhoteperi21:06:54

The JSX return <Header style={style} /> is compiled to React.createElement call so the function returns proper React element

juhoteperi21:06:59

Doesn't happen automatically with Reagent

kennethkalmer21:06:06

aha, makes sense

kennethkalmer21:06:05

this also makes sense why as-element on its own didn’t work, and instead needed to be wrapped now with (fn [props] (reagent.core/as-element [:hiccup]))

kennethkalmer21:06:32

thanks so much for your help on figuring this out! hopefully with this stuff in the readme we can put it to bed for a bit

kennethkalmer21:06:51

Google showed I wasn’t the first person in here asking for help with react-sticky

kennethkalmer21:06:23

I’m knackered, thanks again everyone for chiming in, learned a lot 😴

rgdelato21:06:21

also glad to have learned something new. And the function-as-children pattern isn't too uncommon in React-land, so this'll be useful as I learn more about Reagent

juhoteperi21:06:56

This pattern might be useful even for Cljs components

juhoteperi21:06:58

Like parameterizing autocomplete component items or such

juhoteperi21:06:56

Though in that case the functions might be in props, but maybe there is some benefit in returning Element from the functions

rgdelato21:06:01

in React, it's often used to pass state/callbacks down to children to decouple stuff, whereas it seems like most CLJS projects don't keep a lot of local state in general

juhoteperi21:06:12

It depends, in applications no, but when writing low-level reusable components local state is often necessary or at least very helpful

juhoteperi21:06:48

But there are other ways to handle local state in those components also