我把它放在C9上,因为它有很多依赖项,它可能更容易阅读那里的代码,而不是在这里展示它。
https://ide.c9.io/noman2000/showfer-media
请参阅MainWrapper.jsx
,LibraryView.jsx
,Library.jsx
和connect.js
。
应用程序本身在这里运行:
https://showfer-media-noman2000.c9users.io/
nextjs团队在这里有一个示例应用程序:
https://github.com/zeit/next.js/tree/master/examples/with-redux
但我需要转换我的应用程序,这有点不同。我这样做时给出的错误是:
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.
in Unknown (created by Container)
in AppContainer (created by Container)
in Container (created by App)
in App
重要的一点。我有一个显示此组件Library.jsx
的路线。
// @flow
import React from "react"
import PropTypes from "prop-types"
import routes from "./../../../server/routes/routes"
import commonApi from "./../../../app/common/common"
import LibraryItem from "./../../../app/components/library/LibraryItem"
import detectEnvironment from "./../../../app/common/detect-environment"
const { categoryContent } = commonApi
const { isMobileFromWidth } = detectEnvironment
const { Router } = routes
class Library extends React.Component<Props> {
componentWillMount() {
this.props.actions.setActiveCategory(null, "", -1)
}
authLibraryItems = ["favorites", "history", "queue"]
advtLabel = (label: string) => {
const { library } = this.props.state.toJS()
const sourceUrl = library.serviceTypes[label].source_url
const slashOrder = sourceUrl.substr(8).search("/") + 1
return sourceUrl.substr(8).slice(slashOrder)
}
render() {
const { auth, library, layout } = this.props.state.toJS()
const titles = library.serviceTypes.heading
const categoryClasses = isMobileFromWidth()
? categoryContent(layout.orientation)
: "category-content"
return (
<React.StrictMode>
<section>
<div className={categoryClasses}>
<div className="library-title-container">
<div className="library-title">{titles && titles.title}</div>
<div className="library-subtitle">{titles && titles.subtitle}</div>
</div>
<div className="library-menu scrolling-wrapper">
<h1>I can display!</h1>
</div>
</div>
</section>
</React.StrictMode>
)
}
}
export default Library
该组件包含在网页LibraryView.jsx
。
import connectWrapper from "./../app/redux/utils/connect"
import root from "./../app/redux/rootReducer"
import Library from './../app/components/main/Library'
import MainWrapper from './../app/components/main/MainWrapper'
const { rootActions } = root
export default MainWrapper(connectWrapper(rootActions, Library))
MainWrapper.jsx
看起来像这样:
// @flow
/* eslint-disable */
import root from "window-or-global"
import React from "react"
import { fromJS } from "immutable"
import { connect, Provider } from "react-redux"
import "babel-polyfill"
import storeConfiguration from "../../redux/configureStore"
import rootReducer from "../../redux/rootReducer"
import commonApi from "./../../common/common"
const { getOrCreateStore } = storeConfiguration
export default (...args) => (Component) => {
// First argument is initStore, the rest are redux connect arguments and get passed
const [initStore, ...connectArgs] = args
console.log(Component)
const ComponentWithRedux = (props = {}) => {
const { store, initialProps, initialState } = props
// Connect page to redux with connect arguments
const ConnectedComponent = connect.apply(null, connectArgs)(Component)
// Wrap with redux Provider with store
// Create connected page with initialProps
return React.createElement(
Provider,
{ store: store && store.dispatch ? store : getOrCreateStore(initStore, initialState) },
React.createElement(ConnectedComponent, initialProps)
)
}
ComponentWithRedux.getInitialProps = async (props = {}) => {
const isServer = checkServer()
const store = getOrCreateStore(initStore)
// Run page getInitialProps with store and isServer
const initialProps = Component.getInitialProps
? await Component.getInitialProps({ ...props, isServer, store })
: {}
return {
store,
initialState: store.getState(),
initialProps
}
}
return ComponentWithRedux
}
最后,connect.js
文件。
// @flow
import { connect } from "react-redux"
import { bindActionCreators } from "redux"
import immutable from "immutable"
const connectWrapper = (actions: {}, view: any) => {
const mapStateToProps = state => ({ state })
const mapDispatchToProps = (dispatch: Function) => ({
actions: bindActionCreators(actions, dispatch),
})
return connect(mapStateToProps, mapDispatchToProps)(view)
}
export default connectWrapper
我想要做的是能够将任何组件传递到MainWrapper(connectWrapper(rootActions, <ANY REACT COMPONENT>))
并将其包装在redux存储中,但这不起作用。
这部分由MainWrapper()(connectWrapper(rootActions, <Any React Component>))
解决,但它非常不稳定。
答案 0 :(得分:2)
如果我理解正确,你正在尝试为next.js构建自己的redux-wrapper HOC。我建议使用next-redux-wrapper库,它可以找到here和一个很好的例子。
您只需使用next-redux-wrapper提供的withRedux HOC包装所有页面组件,并且所有子组件都可以包含在react-redux提供的connect函数中,正如它们在docs中所述:
使用withRedux仅包装顶级页面!所有其他组件应该继续使用React Redux的常规连接功能。