反应等待组件从商店获取状态然后呈现子

时间:2018-03-07 22:43:05

标签: javascript reactjs redux

我正在使用react redux。在此Profiles组件中,我使用componentWillMount中的this.startSetUsers来触发从mongodb中提取用户并将其存储到状态。然后我mapStateToProps从状态获取用户作为道具,所以我得到this.props.users。 然后在渲染中我尝试将用户作为道具传递给ProfilesList组件并渲染它,或者如果没有用户从Profile组件中渲染没有用户。

现在这可以工作,如果状态为空并且我导航到ProfilesList或者如果我使用ProfilesList组件刷新该特定URL但是如果通过startSetUser转到ProfilePage组件我只获得一个处于状态的用户并在ProfilePage中显示它然后从那里组件现在状态有一个用户我试图通过<来到ProfilesList链路>显示所有用户< /链接>我得到一个错误“this.props.users.map不是一个函数”,我猜这是因为mapStateToProps在渲染和使用this.props.users.map之前没有完成

我希望有人理解我,这有点拗口。 :D有一些工作吗?

class Profiles extends React.Component {
  componentWillMount() {
    this.props.startSetUsers()
  }

  render() {
    return(
      <div className="content-container content-container--list">
      <div className="list-header">
        <div className="show-for-mobile">Users</div>
        <div className="show-for-desktop">User</div>
        <div className="show-for-desktop">Joined</div>
      </div>
      <div className="list-body">
        {this.props.users.length === 0 ? (
          <div className="list-item list-item--message">
              <span>No users</span>
            </div>
        ) : (
          this.props.users.map((user) => {
            return <ProfilesList key={user._id} {...user} />
          })
        )
      }
      </div>
      </div>
    )
  }
}

const mapStateToProps = (state) => ({
  users: state.user
})

export default connect(mapStateToProps, actions)(Profiles)

ProfilesList

const ProfilesList = ({ username, email, created_at, avatar }) => (
    <Link className="list-item" to={`/user/${username}`}>
      <div className="list-item__avatar-title">
        <div  className="list-item__avatar">
          <img src={avatar || 'https://image.ibb.co/bUv8k7/NoImage.png'} />
        </div>
        <div>
        <h3 className="list-item__title">{username}</h3>
        <span className="list-item__sub-title">{email}</span>
        <br />
        <span className="list-item__sub-title">List of articles: X</span>

        </div>
      </div>
      <div>
        <h4 className="list-item__joined">{moment(created_at).format('MMMM Do, YYYY')}</h4>
      </div>
    </Link>
)

export default ProfilesList;

资料

class Profile extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      usersLoaded: false
    };
  }

  componentWillMount() {
     this.props.startSetUser(this.props.match.params.id)
  }

  render() {
    return(
      <div>
        {
          this.props.user && this.props.match.params.id ?
          <ProfilePage {...this.props}/> :
          <div>404</div>
        }
      </div>
    )
  }
}

const mapStateToProps = (state, props) => ({
  user: state.user
})

export default connect(mapStateToProps, actions)(Profile)

ProfilePage

const ProfilePage = props => {
  const {user} = props;

  return (
    <div className="section">
      <div className="profile__header">
        <div className="profile__name">
          <h2>{`${user.firstName} ${user.lastName}`}</h2>
          <h3>{user.email}</h3>
        </div>
      </div>
      <div className="profile__content">
            <div className="photo-container">
              <div className="photo">
                <img src={user.avatar || 'https://image.ibb.co/bUv8k7/NoImage.png'} />
              </div>
            </div>
            <div className="profile__info">
              <p>Username: <strong>{user.username}</strong></p>
              <li>Email: <strong>{user.email}</strong></li>
              <li>Location: <strong>{user.location}</strong></li>
              <li>City: <strong>{user.city || renderMessage}</strong></li>
              <li>Birthday: <strong>{`${user.day} ${user.month}, ${user.year}`}</strong></li>
              <li>Gender: <strong>{user.gender}</strong></li>
              <li>Joined: <strong>{moment(user.created_at).format('MMMM Do, YYYY')}</strong></li>
            </div>
            <div className="profile__button">
              <button className="button">Edit</button>
              <Link to="/users" className="button">List of all users</Link>
            </div>
      </div>
    </div>
  );
};

export default ProfilePage;

减速器

const userReducer = (state = [], action) => {
  switch (action.type) {
    case 'SET_USER':
      return action.user;
    case 'SET_USERS':
      return action.users;
    default:
      return state;
  }
};

export default userReducer;

编辑:忘记发布动作

// SET_USER
export const setUser = (user) => ({
  type: 'SET_USER',
  user
})

export const startSetUser = (username) => {
  return (dispatch) => {
    axios.get(`${ROOT_URL}/user/${username}`)
      .then(response => {
        dispatch(setUser(response.data))
      })
  }
}

// SET_USERS ALL
export const setUsers = (users) => ({
  type: 'SET_USERS',
  users
})

export const startSetUsers = () => {
  return (dispatch) => {
    axios.get(`${ROOT_URL}/users`)
      .then(response => {
        dispatch(setUsers(response.data))
      })
  }
}

2 个答案:

答案 0 :(得分:0)

看起来你的减速机存在问题:

const userReducer = (state = [], action) => {
  switch (action.type) {
    case 'SET_USER':
      return action.user;
    case 'SET_USERS':
      return action.users;
    default:
      return state;
  }
};

export default userReducer;

您正在使用stateaction.user覆盖action.users。我猜测action.user是一个对象而action.users是一个数组。因此,当ProfileList呈现时,它会看到this.state.users存在,但是您将其设置为对象而不是数组。

我会在userReducer中为activeUser创建一个新属性,或者创建一个新的reducer来处理保存活动用户。

const initialState = {
    activeUser: null,
    users: []
};

const userReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'SET_USER':
      state.activeUser = action.user;
      return state;
    case 'SET_USERS':
      state.users = action.users
      return state;
    default:
      return state;
  }
};

export default userReducer;

答案 1 :(得分:0)

谢谢Chase,你让我思考正确的方向,我设法找到解决方案,减速器确实是问题

我已将减速器更改为此

const userReducer = (state = {}, action) => {
  switch (action.type) {
    case 'SET_USER':
      return { ...state, user: action.payload }
    case 'SET_USERS':
      return { ...state, users: action.payload }
    default:
      return state;
  }
};

export default userReducer;

它有效:)

此处是我更改为使用新更改的减速器

的操作
// SET_USER
export const setUser = (user) => ({
  type: 'SET_USER',
  payload: user
})

export const startSetUser = (username) => {
  return (dispatch) => {
    axios.get(`${ROOT_URL}/user/${username}`)
      .then(response => {
        dispatch(setUser(response.data))
      })
  }
}

// SET_USERS ALL
export const setUsers = (users) => ({
  type: 'SET_USERS',
  payload: users
})

export const startSetUsers = () => {
  return (dispatch) => {
    axios.get(`${ROOT_URL}/users`)
      .then(response => {
        dispatch(setUsers(response.data))
      })
  }
}