开发者问题收集

React Redux 如何使用 ownProps 路由参数进行分派

2016-06-22
2954

我似乎无法弄清楚如何使用路由参数/ ownProps 加载组件/对象,我的配置与 React Redux 应用程序的标准配置基本相同,并且我的操作/减速器工作正常,但对于此组件,数据未预加载。我认为这意味着在定义“用户”对象之前尝试使用它时发生了竞争。我之所以这样认为,是因为它偶尔确实有效 - 它正在经历减速器和 api 调用 - 结果看起来不错。有什么方法我应该先创建一个默认的“用户”对象吗?

路线看起来像

[tld]/user/1234

组件

import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import * as userActions from '../../actions/userActions';
import User from './User';

class UserPage extends Component{
   constructor(props, context){
      super(props, context);
   }

   componentDidMount(){
      this.fetchData();
   }

   fetchData(){
      const {userId} = this.props;
      const {fetchUser} = this.props.actions;
      fetchUser(userId);
   }

   render(){
      // This component when rendered has undefined property exceptions 
      //      though sometimes it works :)
      return(<User user={this.props.currentUser} />);
   }
}

function mapStateToProps(state, ownProps){
   return {
      currentUser: state.user,
      userId: ownProps.params.id
   }
}

function mapDispatchToProps(dispatch){
   return {
      actions: bindActionCreators(userActions, dispatch)
   };
}

export default connect(mapStateToProps, mapDispatchToProps)(UserPage);

更新 所以我想出了一个丑陋的方法在渲染中解决这个问题

return (
    {Object.keys(this.props.currentUser).length > 0 ? 
       <User user={this.props.currentUser} /> ? null }
)

这不可能是正确的方法。 - 我还注意到,如果我只是改变路线 ID,在等待 api 调用返回新用户的延迟时,之前加载的用户会短暂闪现...抱歉,react/redux 对我来说还很新

2个回答

有几种方法可以避免未定义的 props:

1 在 user Reducer 中定义初始状态

const initialState = { user:'', ... };
const user = (state = initialState, action) => {...};
export default user;

2 使用 state.user||""

const mapStateToProps = (state, ownProps) =>({
      currentUser: state.user||"",
      userId: ownProps.params.id
});

3 有时需要在数据加载之前不允许挂载组件。

const LoadingBlock = props => {
    return (<div>{props.isLoading ? 'loading...' : props.children}</div>);
};
LoadingBlock.defaultProps = {
    isLoading: true
};

///then wrap component that will be loading

<LoadingBlock isLoading={this.props.isLoading}>
   <UserComponent user={this.props.user}>
</LoadingBlock>

4 如果 this.props.user 未定义,则不显示 userComponent

render(){
    let {user} = this.props
    return(
        <div>{user && <UserComponent user={user}>}</div>
    )
}

5 如果 this.props.user 不是未定义,则显示组件,否则显示一些“内容”

render(){
    let {user} = this.props
    return(
        <div>{user ? <UserComponent user={user}> : "loading"}</div>
    )
}

6 定义默认值道具

class Control extends React.Component {...}
Control.defaultProps = {value: "somevalue"};

Kokovin Vladislav
2016-06-23

我能想到的几件事:

  1. 检查 this.props.currentUser 是否已定义实际上是一个好主意,但我会使用以下语法:

    const { currentUser } = this.props;
    return currentUser && <User user={currentUser} />;
    
  2. 仅当组件添加到 DOM 时才会调用 componentDidMount。因此,如果 UserPage 组件已在 DOM 中,它将不会触发,并且您的获取代码将永远不会被调用。在这种情况下,您可以使用 componentWillReceiveProps 事件来评估新的 props。 (有关更多信息,请参阅: https://facebook.github.io/react/docs/component-specs.html

  3. fetchUser 到底是做什么的?我假设它是一个异步调用来获取用户数据。您是否使用了一些中间件,例如 redux-thunk?该代码看起来怎么样? 如果您使用 Thunk,则可以分派多个操作来指示获取的状态。因此,如下所示:

    export function fetchUser(userId) {
    return dispatch => {
    dispatch(fetchUserStart());
    someService.fetchUser(userId)
    .then(user => dispatch(fetchUserDone(user)))
    .catch(error => {
    dispatch(fetchUserError(error));
    });
    };
    }
    

    在上面的代码中, fetchUserStartfetchUserDonefetchUserError 都是影响用户状态的操作(此处未显示代码)。 fetchUserStart 可以将用户状态设置为未定义,而 fetchUserDone 将其设置为您从异步获取中获得的用户。由于您的 UserPage 组件与此状态相连,它将通过显示/不显示用户组件做出反应。

0xRm
2016-06-22