Декоратор вместо контейнера
Подключил к react проекту декораторы. В таком виде код работает:
// setTitle.js decorator
/**
title is a string that will be set as a document title
WrappedComponent is what our decorator will receive when
put directly above a component class as seen in the example above
*/
import React from "react";
export const setTitle = getTitle => (WrappedComponent) => {
return class extends React.Component {
updateTitle = (props) => {
// Check if the callback has returned something,
// and if so - update the title
const title = getTitle(props)
if(title) {
document.title = title
}
}
componentDidMount() {
this.updateTitle(this.props)
}
componentWillReceiveProps(props) {
this.updateTitle(props)
}
render() {
return <WrappedComponent {...this.props} />
}
}
}
// Component which is using decorator
@setTitle(()=>'Kamasutra community')
class Community extends React.Component
{
render () {
return <div>
<CommunityListContainerIO />
{/* UpdateCommunity /> */}
</div>
}
}
export default Community;
Теперь хочу чтобы этот декоратор работал с redux, нагружаю декоратор коннектором из react-redux модуля
import React from "react";
import {connect} from "react-redux";
/** SetTitle redux wrapper */
let mapStateToProps = (state) =>
{
return {
/** Page title */
title: state.title
}
}
let mapDispatchToProps = (dispatch) =>
{
return {
/** Follow member with given id */
setTitle: (title) => { dispatch( SetTitleAC(title) ) }
}
}
/** SetTitle decorator */
export const setTitle = (getTitle) => (WrappedComponent) => {
return class extends React.Component {
constructor(props) {
super(props);
document.title = props.title
}
updateTitle = (props) => {
// Check if the callback has returned something,
// and if so - update the title
const title = getTitle(props)
if(title) {
//props.setTitle(title)
}
}
componentDidMount() {
this.updateTitle(this.props)
}
componentWillReceiveProps(props) {
this.updateTitle(props)
}
render() {
//return <WrappedComponent {...this.props} />
return connect(mapStateToProps, mapDispatchToProps)(WrappedComponent)
}
}
}
/** SetTitle reducer */
const SET_TITLE = 'SET_TITLE'
let initialState =
{
title:'kamasutra'
}
const titleReducer = (state = initialState, action) => {
switch (action.type) {
/** Start following user with given userId*/
case SET_TITLE: {
return { ...state, title:state.title }
}
default: return state
}
}
export default titleReducer
export const SetTitleAC = title => { return { type:SET_TITLE, title } }
И ... реакт ругается на использование WrappedComponent в методе connect ...
Error: Objects are not valid as a React child (found: object with keys {$$typeof, type, compare, WrappedComponent}). If you meant to render a collection of children, use an array instead.
Ответы (1 шт):
Автор решения: Sergey Inozemcev
→ Ссылка
Сделал!
/**
title is a string that will be set as a document title
WrappedComponent is what our decorator will receive when
put directly above a component class as seen in the example above
*/
import React from "react";
import {connect} from "react-redux";
/** SetTitle redux wrapper */
let mapStateToProps = (state) =>
{
return {
/** Page title */
title: state.document.title
}
}
let mapDispatchToProps = (dispatch) =>
{
return {
/** Follow member with given id */
setTitle: (title) => { dispatch( SetTitleAC(title) ) }
}
}
/** SetTitle decorator */
export const setTitle = (getTitle) => (WrappedComponent) => {
class SetTitleDecorator extends React.Component {
constructor(props) {
super(props);
document.title = props.title
}
updateTitle = (props) => {
const title = getTitle(props)
if(title) {
document.title = title
}
}
componentDidMount() {
this.updateTitle(this.props)
}
componentWillReceiveProps(props) {
this.updateTitle(props)
}
render() {
return <WrappedComponent {...this.props} />
}
}
const SetTitleDecoratorConnector = connect(mapStateToProps, mapDispatchToProps)(SetTitleDecorator)
return SetTitleDecoratorConnector
}