fahad19 / proppy

Functional props composition for UI components (React.js & Vue.js)

Home Page:https://proppyjs.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Sharing state between components

YahngSungho opened this issue · comments

proppy1

Please refer to the attached gif file.

I tried it the other way, but this.props.setMessages(something) did not change this.props.messages, with
const Proppy = compose( withState('messages', 'setMessages', []) )
and
attach(Proppy)(MyComponent).

It's not complicated at all, so I might have done something wrong, but I do not know what it is. What parts should I check again?

Here is the complete code for that file:

import React, { PureComponent } from 'react'
import { compose, withState } from 'proppy'
import { attach } from 'proppy-react'
import { css } from 'emotion'
// import styled from 'react-emotion'
import { Button, TextArea } from '@blueprintjs/core'
import 'normalize.css/normalize.css'
import '@blueprintjs/core/lib/css/blueprint.css'
import '@blueprintjs/icons/lib/css/blueprint-icons.css'
import { produce } from 'immer'

import { Bubble } from './bubble'

const Proppy = compose(
  withState('messages', 'setMessages', [])
)

const InputField = attach(Proppy)(class extends PureComponent {
  constructor (props) {
    super(props)
    this.state = {
      value: ''
    }
  }

  render () {
    const { messages, setMessages } = this.props
    return (
      <React.Fragment>
        <TextArea
          large fill
          value={this.state.value}
          onChange={(e) => {
            this.setState({
              value: e.target.value
            })
          }}
        />
        <Button text={'ok'} onClick={() => {
          setMessages(
            produce(messages, draft => {
              draft.push(this.state.value)
            })
          )
          this.setState({
            value: ''
          })
        }} />
      </React.Fragment>
    )
  }
})

const ChatWindow = attach(Proppy)((props) => {
  const { messages } = props

  return (
    <div className={css`overflow: auto;`}>
      {messages.map((message) => <Bubble message={message} />)
        // TODO setMyMessage prop 삽입
      }
    </div>
  )
})

class MyComponent extends PureComponent {
  // TODO 이 constructor 없어도 되는거임?
  constructor (props) {
    super(props)
  }

  componentDidMount () {
    this.props.setMessages(this.props.pastMessages)

    // const { setMessages, pastMessages } = this.props
  }

  render () {
    return (
      <React.Fragment>
        <ChatWindow />
        <InputField />
      </React.Fragment>
    )
  }
}

export default attach(Proppy)(MyComponent)

After a couple of experiments, perhaps the problem is that when calling setter() in attach(P)(Comp1), Comp1 is re-rendered, but other attach(P)(Comp2) is not.
Is this the intended behavior of Proppy? Can not multiple components share state through attach?

Hi @YahngSungho,

It is important to understand the difference between Factories and Instances in ProppyJS: https://proppyjs.com/docs/factory-instance/

This is a factory:

const Proppy = compose(
  withState('messages', 'setMessages', [])
)

And you attach the Factory to your Component:

export default attach(Proppy)(MyComponent)

Now when the MyComponent is initialized, it will create an instance out of the ProppyJS factory, and then use it for MyComponent alone.

Same happens with ChatWindow component is initialized, and it has its own ProppyJS instance.

Meaning, the ProppyJS instances are not shared between the two components.

That's where Providers come into play: https://proppyjs.com/docs/providers/

They allow you to share common dependencies of your application throughout the whole components-tree.

If you want to share state between components, I recommend using something like a Store, like Redux for example. There is an integration for that here: https://proppyjs.com/docs/packages/proppy-redux/

Full example: