React没有将状态传递给mapStateToProps

时间:2019-04-13 06:01:00

标签: reactjs redux

我正在尝试在mapStateToProps中传递项目(状态)的数组。但是我得到一个空数组,或者它显示undefined

App.js

import React, { Component } from 'react';
import PostList from './PostList';
import Axios from '../Axios';
import {connect} from 'react-redux';
import { withRouter, Redirect} from 'react-router-dom';
import {DeletePost, GetPosts} from '../actions/';

const Styles = {
    myPaper:{
      margin: '20px 0px',
      padding:'20px'
    }
    , 
    wrapper:{
      padding:'0px 60px'
    }
}
class Posts extends Component {
   state = {
      posts: [],
      loading: true,
    }

  getPosts = () => {
    Axios.get(process.env.REACT_APP_GET_POSTS)
    .then( (res) => {
       this.setState({
          posts: res.data,
          loading: false
        })
    })
    // console.log(this.state.posts);
  }
  componentWillMount(){
    this.getPosts();
  }

  componentDidMount(){
    // doesn't show posts in here
    console.log(this.props.posts)
    this.props.GetPosts(this.state.posts);
  }
  onDelete = (id) => {
    Axios.post(`/api/posts/delete/${id}`);
    this.setState({
      posts: this.state.posts.filter(post => post.id !== id)
    })
  }


  render() {
    const {loading, posts} = this.state;
    if (!this.props.isAuthenticated) {
      return (<Redirect to='/signIn' />);
    }
    if(loading){
      return "loading..."
    }
    return (
      <div className="App" style={Styles.wrapper}>
        <h1> Posts </h1>
        <PostList DeletePost={this.onDelete} posts={posts}/>
      </div>
    );
  }
}
const mapStateToProps = (state) => ({
  isAuthenticated: state.user.isAuthenticated,
  posts: state.user.posts
})
const mapDispatchToProps = (dispatch, state) => ({
  // newPost: (post) => dispatch(newPost(post)),
  // DeletePost: (id) => dispatch( DeletePost(id))
  GetPosts: (posts) => dispatch( GetPosts(posts))
});
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Posts));

Reducer.js

import {  GET_POSTS} from '../actions/';

const initialState = {
    post: [],
    postError: null,
    posts:[]
}

export default (state = initialState, action) => {
    switch (action.type) {
        // doesn't get posts
        case GET_POSTS:
            return({
                ...state,
                posts: action.posts
            })
        default:
            return state
    }

动作

export const GetPosts = (posts) => {
    return (dispatch, getState) => {  
        dispatch({type: GET_POSTS, posts })
        console.log('this works i guess', posts);

    }
}

3 个答案:

答案 0 :(得分:1)

我建议您不要在两个地方保存帖子。这有点违背了使用redux的目的。实际上,您不需要在Posts类中将post作为状态变量使用。每当Redux存储中有新状态时,关联的Class就会进入更新周期。

此外,如果您正在进行api调用,也可以看看redux-thunk

import thunk from 'redux-thunk';
import rootReducer from './reducers/index';

const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);

这将帮助您将api提取逻辑转移到操作和缩减程序上,从而使视图清晰。

更改此

export const GetPosts = (posts) => {
    return (dispatch, getState) => {  
        dispatch({type: GET_POSTS, posts })
        console.log('this works i guess', posts);

    }
}

export const GetPosts = (posts) => {
    return (dispatch, getState) => {
        Axios.get(process.env.REACT_APP_GET_POSTS)
            .then( (res) => {
                 dispatch({type: GET_POSTS, res.data })
             })
        })
    }
}

更改此

componentWillMount(){
    this.getPosts();
  }

componentWillMount(){
    this.props.GetPosts();
  }

现在您将不需要componentDidUpdate

此外,如果您想知道如何显示Loading ...,直到api调用未完成,您可以在商店中添加关键字isFetching。

const initialState = {
    post: [],
    postError: null,
    posts:[],
    isFecthing: false
}

并可以添加诸如ChangeFetchStats之类的操作

export const GetPosts = (posts) => {
    return (dispatch, getState) => {
        dispatch({type: CHANGE_STATE, false});
        Axios.get(process.env.REACT_APP_GET_POSTS)
            .then( (res) => {
                 dispatch({type: CHANGE_STATUS, true);
                 dispatch({type: GET_POSTS, res.data })
             })
        })
    }
}

答案 1 :(得分:0)

所以我终于找到了componentDidupdate的目的

该应用花费了一些时间才能加载帖子,可能需要半秒钟。

因此,通过调用componentDidUpdate,我可以在完成渲染后得到帖子。

  componentDidUpdate(){
    this.props.GetPosts(this.state.posts);     
  }

还有@stevek的另一种解决方案

更改此

 case GET_POSTS:
        return({
            ...state,
            posts: state.posts
        })

对此

import {  GET_POSTS} from '../actions/';

const initialState = {
    post: [],
    postError: null,
    posts:[]
}

export default (state = initialState, action) => {
    switch (action.type) {
        // doesn't get posts
        case GET_POSTS:
            return{...state, posts: action.posts}
        default:
            return state
    }
}

我可以在渲染后看到它

enter image description here

答案 2 :(得分:0)

有时,通过网络获取POST响应可能要花费一些时间。在这种情况下,如果ur组件被挂载,它将调用该动作,但是由于花费时间,您将获得响应为空/未定义的posts数组。 为防止这种情况发生,您可以执行以下操作:

    componentDidMount(){
this.props.GetPosts(this.state.posts);

   if(!this.props.posts){
    console.log(this.props.posts);
}

  }

render方法中的tweek可能也有帮助:

render() {
    const {loading, posts} = this.props;
    if (!this.props.isAuthenticated) {
      return (<Redirect to='/signIn' />);
    }
    if(loading){
      return "loading..."
    }
    return (
{ posts &&(
      <div className="App" style={Styles.wrapper}>
        <h1> Posts </h1>
        <PostList DeletePost={this.onDelete} posts={posts}/>
      </div>
    );)}
  }