Expected component "{Component}" to be prepared but prepareComponent has not been called
Explanation
Possible causes
Your component is a top-level (page) component
If your component is a top-level component and you’re getting this error, there may be an error in the setup of this library. Please verify you have completed the steps in setup instructions. Specifically, make sure you call prepareComponents
for your top-level components in the server-side page rendering function.
prepareComponent() not called at all
Please make sure you have called prepareComponent
for your component…
- from the init action of the current top-level (page) component
or - from the init action of another parent component that has been prepared
If you’re unsure about how this works, please read basic usage in the usage guide.
prepareComponent() is called but the action is not dispatched
You may have forgotton to pass the prepareComponent
action to redux dispatch
:
export default withInitAction(
(props, dispatch) => prepareComponent(MyComponent), // <== forgot to dispatch!
// fix: (props, dispatch) => dispatch(prepareComponent(MyComponent))
)(MyPage);
prepareComponent() is called with the unwrapped (inner) component
You may have exported the unwrapped version of your component. For example:
// MyComponent.jsx
export class MyComponent extends React.Component {
// ...
}
export default withInitAction(
// ...
)(MyComponent);
// another module
import { MyComponent } from './components/MyComponent'; // <== accidentally imported the unwrapped component!
// ...
dispatch(prepareComponent(MyComponent));
In the above example, the default export should be imported instead of the named export:
// fixed
import MyComponent from './components/MyComponent';
prepareComponent() is called from a clientOnly init action
clientOnly
init actions are not called on the server. If this is where you dispatch prepareComponent
, it will not happen in time. For example:
// <Post> Component
export default withInitAction(
['postId', 'authorId'],
{
clientOnly: ({ postId, authorId }, dispatch) => Promise.all([
dispatch(fetchPostComments(postId)),
dispatch(prepareComponent(UserAvatar, { userId: authorId })),
])
}
)(Post);
// <UserAvatar> Component (rendered inside <Post>)
export default withInitAction(
['userId'],
({ userId }, dispatch) => dispatch(prepareUserAvatar(userId))
)(UserAvatar);
There are 3 solutions possible for this:
- split your parent init action between
prepared
andclientOnly
// Change <Post> to: export default withInitAction( ['postId', 'authorId'], { prepared: ({ postId, authorId }, dispatch) => dispatch(prepareComponent(UserAvatar, { userId: authorId })), clientOnly: ({ postId, authorId }, dispatch) => dispatch(fetchPostComments(postId)) } )(Post);
- make the entire parent action
prepared
// Change <Post> to: export default withInitAction( ['postId', 'authorId'], ({ postId, authorId }, dispatch) => Promise.all([ dispatch(fetchPostComments(postId)), dispatch(prepareComponent(UserAvatar, { userId: authorId })), ]) )(Post);
- change all child components of
clientOnly
actions to also beclientOnly
// Change <UserAvatar> to: export default withInitAction( ['userId'], { clientOnly: ({ userId }, dispatch) => dispatch(prepareUserAvatar(userId)) } )(UserAvatar); // Change <Post> to: export default withInitAction( ['postId', 'authorId'], { clientOnly: ({ postId, authorId }, dispatch) => dispatch(fetchPostComments(postId)), // prepareComponent no longer necessary for clientOnly UserAvatar } )(Post);