首页 > 解决方案 > 尝试在 ComponentDidMount 中使用异步承诺填充道具

问题描述

所以在我不受控制的 PossibleMatches 组件内部,我从 React 的工作方式知道,初始渲染阶段将使用空的 prop 值(如果这些 prop 值依赖于外部应用程序状态(mapStateToProps))发生,无论我是否有 componentDidMount 生命周期方法或构造函数设置。作为对此的回应,我在 componentDidMount 中设置了一个 Promise,这样当我调度 prop 函数 [defaultPieces,arrangePieces] 时,我可以让 UI 呈现一个 ActivityIndi​​cator 以指示当前正在获取的东西。问题是,当我从承诺的成功阶段调用 mapStateToProps 时,我似乎无法让 mapStateToProps 函数理解状态。这里是:

class PossibleMatches extends Component {
    constructor(props){
        super(props);
    }

componentDidMount(props){
    return new Promise((resolve, reject) => {
        let state;
        let {defaultPieces, arrangePieces, isFetching} = this.props;
        let makeClothesAppear = function(){
            defaultPieces();
            arrangePieces();
            isFetching = true;
        }

        resolve(makeClothesAppear());
    }).then(function(state){
        mapStateToProps(state);
        this.props.isFetched = true
        this.props.isFetching = false;
    }).catch((error) => {
        console.log('FetchClothesError: ', error);
    })
}
}

UI 如何决定显示什么:

renderDecision(){

        const {UpperComponents, LowerComponents} = this.props;
        const {currentUpperComponent, currentLowerComponent} = this.state.currentComponent.whichPiece;
        const {LowerComponentEnabled, UpperComponentEnabled} = this.state;

        if (this.props.isFetching){
             return (<div className='activityLoader'>
                        <ActivityIndicator number={3} duration={200} activeColor="#fff" borderWidth={2} borderColor="50%" diameter={20}/>
                     </div>);
        } else if (this.props.isFetched){
                return (<div className = "PossibleMatches_Container">
                        <i className = 'captureOutfit' onClick = {this.snapshotMatch}></i> 
                            {UpperComponents.map((component) => {                               
                                    return (<UpperComponent key={component.createdAt} id={component.id} 
                                               switchComponent={this.switchFocus} 
                                               setCurrentPiece = {this.setNewPiece} 
                                               evaluatePiece={this.isOppositeComponentSuggested}
                                               image={component.image}
                                               toggleToPiece = {(LowerComponentEnabled) => {if (LowerComponentEnabled === false){this.setState({LowerComponentEnabled: true})}else{return;} this.setState({currentLowerComponent: this.props.suggestedBottoms[0]})}} 
                                               isLowerComponentEnabled={LowerComponentEnabled}
                                               ref={this.residingUpperComponent}
                                               className = {this.state.currentComponent.whichPiece.whichType === 'match' ? 'PossibleMatches_Container' : this.state.currentComponent.whichPiece.whichType === 'bottom' ? 'standalonePiece' : 'standalonePiece'}/>)
                                    })
                            }
                            {LowerComponents.map((component) => {
                                    return  (<LowerComponent key={component.createdAt} id={component.id} 
                                               setCurrentPiece = {this.setNewPiece} 
                                               evaluatePiece={this.isOppositeComponentSuggested}
                                               image={component.image}
                                               toggleToPiece={(UpperComponentEnabled) => {if (UpperComponentEnabled === false){this.setState({UpperComponentEnabled: true})}else{return;} this.setState({currentUpperComponent: this.props.suggestedTops[0]})}}                
                                               switchComponent={this.switchFocus}
                                               isUpperComponentEnabled={UpperComponentEnabled}
                                               ref={this.residingLowerComponent}
                                               className = {this.state.currentComponent.whichPiece.whichType === 'match' ? 'PossibleMatches_Container' : this.state.currentComponent.whichPiece.whichType === 'bottom' ? 'standalonePiece' : 'standalonePiece'}/>)                                                  
                                    })
                            }
                        </div>)
        }
    }

    render(){


        return(  

                <div className = 'GorClothingContainer'>
                    {/*<Wardrobe upperComponent={this.state.currentComponent.whichPiece.currentUpperComponent} lowerComponent={this.state.currentComponent.whichPiece.currentLowerComponent} enableCapture={(snapshot) => this.snapshotMatch = snapshot} />*/}
                      {this.renderDecision()}
               </div>
            );
    }

My PossibleMatches 减速器

import {INITIAL_PIECES, GET_ANCILLARY_PIECES, ORGANIZE_PIECES, SET_CONTEMPLATED_PIECE} from '../actions/types';

const initialState = {
     UpperComponents: [],
     LowerComponents: [],
     contemplated_piece: null,
     extraTops: [],
     extraBottoms: [],
     standaloneTops: [],
     standaloneBottoms: [],
     suggestedTops: [],
     suggestedBottoms: []
}

export default function(state = initialState, action){

    switch(action.type){
        case INITIAL_PIECES:
            return Object.assign({}, state, {contemplated_piece: action.payload.contemplated_piece},
                                            {extraTops: action.payload.extra_tops},
                                            {extraBottoms: action.payload.extra_bottoms},
                                            {standaloneTops: action.payload.standalone_tops},
                                            {standaloneBottoms: action.payload.standalone_bottoms},
                                            {suggestedTops: action.payload.suggested_tops},
                                            {suggestedBottoms: action.payload.suggested_bottoms})
        case GET_ANCILLARY_PIECES:
           return Object.assign({}, state, {extraTops: action.payload.extra_tops},
                                           {extraBottoms: action.payload.extra_bottoms},
                                           {standaloneTops: action.payload.standalone_tops},
                                           {standaloneBottoms: action.payload.standalone_bottoms},
                                           {suggestedTops: action.payload.suggested_tops},
                                           {suggestedBottoms: action.payload.suggested_bottoms})
        case ORGANIZE_PIECES:
               return Object.assign({}, state, {UpperComponents: action.payload.UpperComponents},
                                               {LowerComponents: action.payload.LowerComponents})           
        case SET_CONTEMPLATED_PIECE:
           return Object.assign({}, state, {contemplated_piece: action.payload.contemplated_piece})
        default:
            return state;
    }
}

我的 combineReducers 段

import {combineReducers} from 'redux';

const allReducers = combineReducers({
 Playlist: PlaylistReducer,
 eventOptions: eventTicketReducer,
 possibleMatches: PossibleMatchesReducer,
 Intro: combineForms({
        basicUserInfo: BasicUserInfoState,
        GenderInfo: GenderInfoState,
        ContactInfo: ContactInfoState
       }, 'Intro'),
 routing: routerReducer,
 form: formReducer
});

道具值:

PossibleMatches.defaultProps = {
    isFetching: true,
    isFetched: false
}

我的 mapStateToProps 函数

function mapStateToProps(state){

            return {UpperComponents: state.possibleMatches.UpperComponents,
                    LowerComponents: state.possibleMatches.LowerComponents,
                    contemplatedPiece: state.possibleMatches.contemplated_piece,
                    extraTops: state.possibleMatches.extraTops,
                    extraBottoms: state.possibleMatches.extraBottoms,
                    standaloneTops: state.possibleMatches.standaloneTops,
                    standaloneBottoms: state.possibleMatches.standaloneBottoms,
                    suggestedTops: state.possibleMatches.suggestedTops,
                    suggestedBottoms: state.possibleMatches.suggestedBottoms}
}

function mapDispatchToProps(dispatch){
      return {
        defaultPieces: () => {
          dispatch(defaultPieces())
        },
        arrangePieces: () => {
            dispatch(arrangePieces())
        },
        getCorrespondingPieces: () => {
            dispatch(getCorrespondingPieces())
        },
        setEvaluatedPiece: () => {
            dispatch(setEvaluatedPiece())
        }
      }
    }

export default connect(mapStateToProps, mapDispatchToProps)(PossibleMatches)

我的问题是:我实现承诺的方式到底有什么问题。正确设置 reducer 和 redux 操作(我知道是因为我已经从 redux 操作文件将获取的项目记录到控制台),如何正确填充 mapStateToProps 中的 prop 值。目前的错误是:

在此处输入图像描述

我使用反应 16.4.0

标签: javascriptreactjsredux

解决方案


一个简单的 redux 用例如下所示

possibleMatches.jsx(组件文件)

class PossibleMatches extends React.Component {
  state = {
    isFetching: false
  }

  componentDidMount() {
    this.setState({isFetching: true})
    fetchingSomethingFromServer()
    .then(resp => {
      this.setState({isFetching: false})
      this.props.UpdateRedux(resp)
    });
  }

  render() {
    const { isFetching } = this.state;
    const { data } = this.props;
    return (
      isFetching ? <div>loading...</div> : <div>{data}</div>
    )
  }
}

export default connect(state => ({ data: state.possibleMatches.data }), {UpdateRedux})

actions.js(动作创建者文件)使用此动作将任何数据更新到 redux

export const UpdateRedux = (data) => {type: 'UPDATE_REDUX', payload: data}

reducers.js 这是保存 redux 状态的文件

const defaultState = {
 data: null
}

export default (state = defaultState, action) => {
  switch(action.type) {
    case 'UPDATE_REDUX':
      return {data: action.payload};
    default:
      return state
  }
}

在您的组合减速器中导入此减速器并将其分配如下

import possibleMatches from 'reducers.js';

combineReducers({ possibleMatches });

推荐阅读