0

I'm playing around with Flux and it's working great but I'm now trying to use it in a way where a flux store determines a single point of truth or state for all child components.

I'm basically trying to implement an auth system, which determines the auth state of the current user without having to update the state of each component individually (there are lots of them) by doing something like this :

state = {
    authenticated: AuthStateStore.getState(),
    uid: AuthStateStore.getUid(),
    token: AuthStateStore.getToken(),
    username: AuthStateStore.getUsername(),
    avatar: AuthStateStore.getAvatar(),
    errors: []
}

I thought I could set the state on the main parent <App/> component (from which everything else is rendered as children) and then pass the state down as props to all children. This indeed works - {this.props.state.authenticated} will show the correct state from <App/> in the children - but props are immutable, meaning that when the state of <App /> is updated via a flux store, none of the props being sent to children are updated with the new values from <App/>.

Is there any way to achieve what I'm trying to do here or do I have to set the state from the flux store in every component that requires the info in this way?

EDIT: how I'm passing the state down from <App/> (I've trimmed the fat so they are more readable).

App (Main parent)

class App extends Component {
  state = {
    authenticated: AuthStateStore.getState(),
    uid: AuthStateStore.getUid(),
    token: AuthStateStore.getToken(),
    username: AuthStateStore.getUsername(),
    avatar: AuthStateStore.getAvatar()
  }

  render() {
    return (
      <BrowserRouter>
        <div>
          <Sidebar state={this.state}/>
          <Switch>
            <Route exact path="/" component={Home} state={this.state}/>
            <Route exact path="/signup" component={Signup} state={this.state}/>
            <Route path="/activate/([\da-f]+)" component={Activate}/>
            .......
          </Switch>
          <Footer />
        </div>
      </BrowserRouter>
    );
  }

}

Sidebar (first child)

class Sidebar extends Component {

  render() {
    return (
      <div className="sidebar">
        <Navigation state={this.props.state}/>
        <Search/>
      </div>
    );
  }

}

Navigation (Second child)

class Navigation extends Component {

  render() {
    if (this.props.state.authenticated === "true") {
      return (
        <div>
          <p>Authenticated content here</p>
        </div>
      );
    } else {
      return (
        <div>
          <p>Non-authenticated content here</p>
        </div>
      );
    }
  }

}

The above code works on first load, but if the state of <App/> changes via the flux store, this isn't reflected in the children unless you do a full page reload (which we obviously don't want to do).

Further Edit...

Just to be concise, right now I have everything working by doing the following in each child component that requires the Auth state info (again fat trimmed for readability)...

class Navigation extends Component {
  state = {
    authenticated: AuthStateStore.getState(),
    uid: AuthStateStore.getUid(),
    token: AuthStateStore.getToken(),
    username: AuthStateStore.getUsername(),
    avatar: AuthStateStore.getAvatar()
  }

  componentWillMount() {
    AuthStateStore.on("change", () => {
      this.setState({
        authenticated: AuthStateStore.getState(),
        uid: AuthStateStore.getUid(),
        token: AuthStateStore.getToken(),
        username: AuthStateStore.getUsername(),
        avatar: AuthStateStore.getAvatar()
      });
    });
  }

  render() {
    if (this.state.authenticated === "true") {
      return (
        <div>
          <p>Authenticated content here</p>
        </div>
      );
    } else {
      return (
        <div>
          <p>Non-authenticated content here</p>
        </div>
      );
    }
  }

}

... but in the spirit of DNRY, and trying to avoid any potential pitfalls due to forgetting to call or set a state in a component somewhere, I'm looking for an alternative 'one-stop-shop' solution which I was hoping flux could provide.

spice
  • 1,442
  • 19
  • 35
  • You need to share how you are passing the props from App state down to the child component. – jmargolisvt Oct 20 '18 at 14:52
  • @jmargolisvt done :) – spice Oct 20 '18 at 15:23
  • This post has given me a few insights - https://stackoverflow.com/questions/26089532/why-cant-i-update-props-in-react-js - but to be honest, it seems to be much easier and less contrived doing it the way I'm already doing it. Any thoughts? – spice Oct 20 '18 at 15:59
  • You should start with fixing this: `` Passing component-local state as a prop is an anti-pattern. I don't know about Flux, but in Redux you would `mapStateToProps` so that the props update the children. – jmargolisvt Oct 20 '18 at 17:07

0 Answers0