设置我的第一个react / redux项目。
我正在尝试构建一个Page
高阶组件,该组件可以到达外部api以获取页面的“框架”:导航,面包屑,通知,标题。由于我有多个页面,我认为这对于HOC来说是一个很好的用例。
这个想法是从api获取数据并将其保存在Redux存储中。每个页面都是一个包含在withPage
HOC中的容器。
在我尝试更新redux商店之前,一切正常。更新状态会导致HOC组件和/或包装组件重新呈现,从而导致循环。
让我们看看一些代码,不管吗?
// WrappedComponent
import React, { Fragment, Component } from 'react';
import { connect } from 'react-redux';
import withAuthentication from '../../hoc/withAuthentication';
import withPage from '../../hoc/withPage/withPage';
// import styles from './Welcome.css';
class Welcome extends Component {
render() {
return (
<Fragment>
<p>Welcome to React!</p>
<p>Welcome to React!</p>
</Fragment>
);
}
}
const mapStateToProps = state => ( {
loaded: state.page.loaded,
} );
export default connect( mapStateToProps )( withAuthentication( withPage( Welcome, 187 ) ) );
// withPage HOC
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { fetchPage } from './store';
export default ( ComposedComponent, pageId ) => {
class Page extends Component {
componentDidMount() {
this.props.onPageFetch( this.props.token, pageId );
}
render() {
return <ComposedComponent { ...this.props } />;
}
}
Page.propTypes = {
onPageFetch: PropTypes.func.isRequired,
};
const mapDispatchToProps = dispatch => ( {
onPageFetch: ( token, id ) => dispatch( fetchPage( token, id ) ),
} );
const mapStateToProps = state => ( {
loaded: state.page.loaded,
} );
return connect( mapStateToProps, mapDispatchToProps )( Page );
};
// ducks
import axios from '../../axios-internal';
import { updateObject } from '../../utils/utility';
// ACTIONS
const FETCH_PAGE_START = 'FETCH_PAGE_START';
const FETCH_PAGE_SUCCESS = 'FETCH_PAGE_SUCCESS';
const FETCH_PAGE_FAIL = 'FETCH_PAGE_FAIL';
// ACTION CREATORS
export const fetchPageStart = () => ( {
type: FETCH_PAGE_START,
} );
export const fetchPageSuccess = ( payload ) => {
return {
type: FETCH_PAGE_SUCCESS,
payload,
};
};
export const fetchPageFail = error => ( {
type: FETCH_PAGE_FAIL,
error,
} );
export const fetchPage = ( token, pageId ) => ( dispatch ) => {
dispatch( fetchPageStart() );
axios.get( 'page-187.json' )
.then( ( res ) => {
const crumbs = res.data.data.crumbs;
const page = res.data.data.page;
const sidebar = res.data.data.sidebar;
// This is introducing the state update loop
dispatch( fetchPageSuccess( {
crumbs: crumbs,
page: page,
sidebar: sidebar,
} ) );
} )
.catch( ( err ) => {
dispatch( fetchPageFail( err ) );
} );
};
// REDUCERS
const initialState = {
crumbs: null,
page: null,
sidebar: null,
loading: true,
loaded: false,
};
const helperFetchPageStart = ( state, action ) => updateObject( state, { loading: true } );
const helperFetchPageSuccess = ( state, action ) => updateObject( state, {
crumbs: action.payload.crumbs,
page: action.payload.page,
sidebar: action.payload.sidebar,
loading: false,
loaded: true,
} );
const helperFetchPageFail = ( state, actions ) => updateObject( state, { loading: false } );
const reducer = ( state = initialState, action ) => {
switch ( action.type ) {
case FETCH_PAGE_START: return helperFetchPageStart( state, action );
case FETCH_PAGE_SUCCESS: return helperFetchPageSuccess( state, action );
case FETCH_PAGE_FAIL: return helperFetchPageFail( state, action );
default: return state;
}
};
export default reducer;
请注意ducks.js中的注释,指示导致循环的调度操作。
这也可能是对我如何使用HOC的误解。