React Redux如何使用ownProps路由参数

时间:2016-06-22 20:26:22

标签: reactjs redux react-redux

我似乎无法弄清楚如何使用路由参数/ ownProps加载组件/对象我的配置基本上与react redux应用程序的标准相同,我的actions / reducers工作正常但是对于此组件数据未预先加载。我假设这意味着在定义它之前尝试使用'user'对象时会发生竞争。我假设这是因为它偶尔会起作用 - 它通过reducer(s)和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 个答案:

答案 0 :(得分:2)

有办法避免未定义的道具:

1 在用户缩减器中定义初始状态

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

2 使用state.user||""

处理mapStateToProps中未定义的内容
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未定义,则显示组件,否则显示一些&#34;内容&#34;

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

6 定义默认道具

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

答案 1 :(得分:1)

我能想到的一些事情:

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

    const { currentUser } = this.props;
    return currentUser && <User user={currentUser} />;
    
  2. 仅在将组件添加到DOM时调用componentDidMount。因此,如果UserPage组件已经在DOM中,它将不会触发,并且永远不会调用您的提取代码。在这种情况下,您可以使用componentWillReceiveProps事件来评估新道具。 (参见: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));
          });
      };
    }
    

    在上面的代码fetchUserStart中,fetchUserDonefetchUserError都是影响用户状态的所有操作(此处未显示的代码)。 fetchUserStart可以将用户状态设置为undefined,而fetchUserDone将其设置为您从异步提取获得的用户。当您的UserPage组件连接到此状态时,它将通过显示/不显示用户组件来做出反应。