I'm exploring react/redux and I'm trying to work out the best way to implement a multi-step wizard component where the Next "step" (i.e. component) is dynamically determined at runtime based on server-side workflow rules. I looked at redux-form and other wizard-like components but only saw hard-coded steps like this example from redux-form (props omitted for brevity):
return (<div>
{page === 1 && <WizardFormFirstPage />}
{page === 2 && <WizardFormSecondPage/>}
{page === 3 && <WizardFormThirdPage />}
</div>
)
My first (naive) experiment toward a dynamic solution involved the following function for rendering a given component into a host div (I'm using the term "host" instead of "container" to avoid ambiguity with Dan Abramov's concept of "container components"):
showComponent(componentName) {
let renderFunc = React.createElement(components[componentName], null);
render(renderFunc, this.refs['hostDiv']);
}
This works with [simple] presentational components - yay... Of course, this is useless because the newly rendered component doesn't get any props.
My next experiment was to see if this would work with redux-connected container components. As you surely can guess, I failed miserably; if componentName
refers to a container component, I get:
Uncaught Invariant Violation: Could not find "store" in either the context or props of "Connect(Borrowers)". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(Borrowers)".
The error message is telling me how stupid I am for passing null
as the second argument to createElement()
. So here's the next iteration:
showComponent(componentName) {
const { store } = this.context;
let renderFunc = React.createElement(components[componentName], { store });
render(renderFunc, this.refs['hostDiv']);
}.
This makes redux happy and seems to work. However, I don't feel great about using React's experimental context feature. This should typically be reserved for libraries.
So...
Q1. Is there a recommended way to dynamically render a component and wire it up to the redux store in a seamless manner, as if it were part of the static component hierarchy (including preserving time travel debugging and not screwing up React's VDOM reconciliation process)?
Q2. Does anyone foresee any problems with my approach (barring the usage of context)?
Q3. What are the performance implications of my approach, with regards to VDOM reconciliation?
Note: I tagged "react-router" because I'm open to a router-based approach as well. Keep in mind, I won't know my routes until runtime. I know react-router supports dynamic routing with code splitting, but I'm not sure I can inject/replace new routes at runtime.
Edit: I've stricken the above because I think any router solution would be encapsulated in a HOC and the componentName
would simply be passed down via props to the actual presentation component in question.
react-router
's routing? You can have dynamicparams
in url to match. – Yuya