State machines and UI: Rendering based on 'node-level' states instead of 'leaf' states

馋奶兔 提交于 2019-12-05 00:08:07

Let's try to propose a solution for your architectural problem. Not sure if it will be satisfactory since I am not fully confident in my understanding of your problem.

Let's take your problem from the point you start having real problems, the Exam component tree.

As you stated, the problem is that you need to replicate your leafs in each possible 'Node State'.

What if you could make some data accesible for any of the components in the tree? For my this sounds like a problem that could use the Context API that React 16+ provides.

In your case I will create a Provider that wraps my whole application / Branch of the tree that I am interested in sharing a context with:

In this way you could access your context from any of the components and it can be modified dynamically and through redux.

Then is just left for your UI Components to keep the logic to deal with the UI State provided or computed with the given context. The rest of the application can keep it structure without complicating the lower levels or duplicating nodes, you just need to add a wrapper (Provider) in order to make the Context available.

Some examples of people using this:

Material UI <- They pass the theme as a context and access it whenever and wherever (The theme can also be change dynamically). Very similar to the locale case that you showed. WithStyles is a HOC that links a component to the theme in the state. So that simplified:

ThemeProvider has theme data. Under it there can be Routes, Switch, Connected components (Very similar to your nodes if I understood right). And then you have components that used with withStyles have access to the theme data or can use the theme data to compute something and it is injected in the component as a prop.***

And just to finish I can draft kind of an implementation in few lines (I didn't try it out but it is just for explanation purposes using the Context explanation):

QuestionStateProvider

export const QuestionState = React.createContext({
  status: PLAYING,
  pause: () => {},
});

AppContainer

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      status : PLAYING,
    };

    this.pause = () => {
      this.setState(state => ({
        status: PAUSE,
      }));
    };
  }

  render() {
    return (
      <Page>
        <QuestionState.Provider value={this.state}>
          <Routes ... />
          <MaybeALeaf />
        </ThemeContext.Provider>
        <Section>
          <ThemedButton />
        </Section>
      </Page>
    );
  }
}

Leaf - It is just a container that gets questions from the state and render a question or more...

Q1

function Question(props) {
  return (
    <ThemeContext.Consumer>
      {status => (
        <button
          {...props}
          disable={status === PAUSED}
        />
      )}
    </ThemeContext.Consumer>
  );
}

I hope I got your question right and that my words are clear enough.

Correct me if I understood you wrongly or if you want to discuss further.

*** This is a extremely vague and general explanation of how material ui theming works

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!