Skip to content
This repository has been archived by the owner on Feb 19, 2022. It is now read-only.

State not being updated #34

Closed
KadoBOT opened this issue May 5, 2017 · 2 comments
Closed

State not being updated #34

KadoBOT opened this issue May 5, 2017 · 2 comments

Comments

@KadoBOT
Copy link

KadoBOT commented May 5, 2017

State is available to the component, so does the effects. (They are in different folders, effects is one folder above, dunno if that makes any difference to my problem).

// initial-state.js
export default () => ({
  selected: "internal",
  isOpen: true
})
// effects.js
export default {
  handleDialog: () => state => ({ ...state, isOpen: !state.isOpen })
}

PS: I've tried SoftUpdate and Object.assign as well in the above function.

// React Component that triggers the effects
const NavButtons = ({ effects }) => (
  <Wrapper>
    <RaisedButton primary label="Request Appraisal" onClick={effects.handleDialog} />
  </Wrapper>
);

NavButtons.propTypes = {
  effects: PropTypes.shape({
    handleDialog: PropTypes.func.isRequired
  }).isRequired
};

export default injectState(NavButtons);
// React component that holds the mentioned state
const RequestAppraisal = ({ state, effects }) => {
  const actions = [
    <RaisedButton label="Submit" primary onTouchTap={effects.handleDialog} />
  ];

  return (
    <Dialog
      autoScrollBodyContent
      title="Create new feedback round"
      actions={actions}
      modal={false}
      open={state.isOpen}
    >
      <RowWrapper>
        <RowTitle>Survey Template</RowTitle>
        <Wrapper>
          <SurveyTemplate />
        </Wrapper>
      </RowWrapper>
      <RowWrapper>
        <RowTitle>Type of Feedback</RowTitle>
        <Wrapper>
          <TypeOfFeedback />
        </Wrapper>
      </RowWrapper>
      <RowWrapper>
        <RowTitle>Add Assessors</RowTitle>
        <Wrapper>
          <AddAssessors />
        </Wrapper>
      </RowWrapper>
      <RowWrapper>
        <Wrapper>
          <Assessors />
        </Wrapper>
      </RowWrapper>
    </Dialog>
  )
}

RequestAppraisal.propTypes = {
  state: PropTypes.shape({
    isOpen: PropTypes.bool.isRequired
  }).isRequired,
  effects: PropTypes.shape({
    handleDialog: PropTypes.func.isRequired,
  }).isRequired
};

export default provideState({
  initialState
})(injectState(RequestAppraisal));

The problem is that the despite being available to the component, the state is only updated if I use the state/effect in the parent component. If I just inject/provide without using them, the state does not update.

Here is an example:
The component above doesn't update if the App.js written like this:

const Dashboard = () => (
  <div>
    <NavBar />
    <Wrapper>
      <UserInfo />
      <DashboardData />
      <RequestAppraisal />
    </Wrapper>
  </div>
);

export default withState(injectState(Dashboard));

But it does update if App.js has props state:

// NavButtons component is inside NavBar.
const Dashboard = ({ state }) => (
  <div>
    {console.log(state.isOpen)}
    <NavBar />
    <Wrapper>
      <UserInfo />
      <DashboardData />
      <RequestAppraisal />
    </Wrapper>
  </div>
);

export default withState(injectState(Dashboard));

Is that the correct behaviour? Because like in my example, I don't need to use the state/effects in the parent component.
Or I am doing something wrong?

Thanks

@KadoBOT
Copy link
Author

KadoBOT commented May 5, 2017

So, I've figured that an effect doesn't know the state of its children, and that's why it's not working

TL;DR: Is it possible to update a child state from a parent effects?

@divmain
Copy link
Contributor

divmain commented May 8, 2017

Hi @KadoBOT, it is not possible to update child state from a parent effect. The idea is that a piece of state and the effects that transform it should be co-located. If a piece of state needs to live closer to the root of the component tree, so should the corresponding effect, and vice versa.

If I'm reading your example correctly, I would say that the isOpen state atom "belongs" to the Dashboard. It is updated from the grand-child <NavButtons /> and consumed by child <Dashboard />.

Generally speaking, if you want to access and/or transform a piece of state from more than one component in different parts of your application, the effect and state atom should be owned by the closest common ancestor of those components.

I hope that helps. Feel free to reach out again if I need to clarify or dig into anything in particular.

@divmain divmain closed this as completed May 8, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants