将Redux存储中的对象数组渲染为React组件

时间:2020-01-10 08:31:17

标签: javascript reactjs redux react-redux

我正在尝试显示商店中的初始状态。我知道我的代码不正确,但我希望为此学习最简单的方法。我可以简单地使用道具从商店接收数据吗?还是我需要一些生命周期事件来定位存储中的数据?

这是我当前的尝试:我对其进行了编辑,以包括我的减速器,并根据以下评论更新了组件。


//store .js

import { createStore, applyMiddleware,compose } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers'; //the index.js file

const initialState = {

}

const middleware = [thunk]

const store = createStore(
    rootReducer, 
    initialState, 
    compose(
    applyMiddleware(...middleware),
    window.__REDUX_DEVTOOLS_EXTENSION__&& window.__REDUX_DEVTOOLS_EXTENSION__()
)
);

export default store;

现在,当尝试在以下组件中绘制道具时,出现错误:

this.props.properties.map is not a function

//Properties component that renders a map of my props

import React, { Component } from 'react'
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {getListings} from '../actions/postActions';

 class Properties extends Component {

    componentDidMount(){
        getListings()
    }

    render() {
        const properties = this.props.properties.map(property => (
            <div key = {property.id}>
                <h3>{property.propertyName}</h3>
                <div style={{width: '4em', height:'4em', backgroundColor: 'blue'}}>image</div>
                <p>{property.footage}</p>
                <p>{property.address}</p>
                <p>{property.price}</p>
            </div>
        ))
        return (
            <div>
                <h1>Current Listings</h1>
                    {properties}
            </div> 
        )
    }
}
Properties.propTypes = {
    properties: PropTypes.array.isRequired,
    newListing: PropTypes.object
}

const mapStateToProps = state =>({
    properties: state.properties.properties,
    newListing: state.properties.newListing
});
export default connect(mapStateToProps)(Properties)

//my actionsHandler.js

import {GET_LISTINGS, NEW_LISTING} from './types';


export function newProperty(formdata){
    return function(dispatch){
        dispatch({
            type: NEW_LISTING,
            payload: formdata
        })
    }
}

export function getListings(form){
    return function(dispatch){
        dispatch({
            type: GET_LISTINGS,
        })
    }
}
//my reducer
import {NEW_LISTING, GET_LISTINGS} from '../actions/types';

const initialState={
    properties: [
        {
            id: 1,
            propertyName: 'The boogaloo',
            footage: '3500 sqft',
            address: '123 hill bounty rd',
            price:'$ 350,000.00'
        }
    ],
    newListing: {}
}

export default function(state=initialState, action){
    switch(action.type){

        case NEW_LISTING:
            return{
                ...state,
                properties:state.properties.push(action.payload)
            }
        case GET_LISTINGS:
            return{
                state
            }

        default:
            return state
    }
}

3 个答案:

答案 0 :(得分:3)

使用生命周期方法更新组件

像shouldComponentUpdate方法,

道具变更不仅会导致重新呈现,而且状态变更也会导致重新呈现, 这种情况下存储道具是因为状态也是一种解决方案(不合适)

答案 1 :(得分:1)

在redux中,您将在reducer中定义一个初始状态,并将使用操作对状态中的数据进行一些更新或删除,并将进行存储(即,您正在更新对象),初始状态对象将被更新。在这种情况下,您直接需要初始状态。因此,您需要复制初始状态对象并对其执行任务。当新对象更新时,初始状态将不起作用。

您可以通过直接从组件(即mapdispatchtoProps)中调度动作来使用组件进行更新。

您可以通过连接来访问组件中的整个商店数据,即connect(mapStatetoProps,mapDispacthtoProps)。

mapSatettoProps将使您将数据存储为状态。您可以修改它,也可以做任何您想做的事。状态访问也可以在组件中完成,但是您将获得更新。

答案 2 :(得分:1)

您的一般方法总体上可行,但需要进行某些更正:

  • 您的状态应该是一个对象(不是当前的数组)
  • 为了使整个对象数组显示为一堆React元素,您可能需要将它们包装到某个父组件中,map()将您的各个帖子作为小组件接收来自父对象的相应对象作为道具组件

您可以查询以下现场演示作为参考:

//dependencies
const { render } = ReactDOM,
      { createStore } = Redux,
      { connect, Provider } = ReactRedux
      
//initial state, doomy reducer and basic store (no middleware)
const initialState = {posts:[{id:'0',propertyName:'house',footage:'1800 sqft',address:'108 boogaloo dr. thisplace, CA',price:'$145,300.00'},{id:'1',propertyName:'closet',footage:'110 sqft',address:'23 dirt dr. badplace, NC',price:'$3'},{id:'2',propertyName:'garage',footage:'1000 sqft',address:'10 meadow st. decent, NY',price:'$100,000.00'},{id:'3',propertyName:'fishing shack',footage:'500 sqft',address:'108 fishy dr. forestgrove, NJ',price:'$200,300.00'},{id:'4',propertyName:'huge mansion',footage:'8000 sqft',address:'32 T-Pain st. onlytwentythree, WI',price:'$100.00'},{id:'5',propertyName:'dog house',footage:'200 sqft',address:'2367 goodboy dr. borks, KA',price:'$1000.00'},{id:'6',propertyName:'beehive',footage:'too big to measure',address:'108 stingya dr. Bidibi, NJ',price:'$300.00'},{id:'7',propertyName:'my house',footage:'4000 sqft',address:'42 treeface dr. bigwoods, FL',price:'$190,300.00'},]},
      appReducer = (state=initialState, action) => state,
      store = createStore(appReducer)
//post ui component
const Post = ({propertyName, footage, address, price}) => (
  <div>
    <h3>{propertyName}</h3>
    <p>footage: {footage}</p>
    <p>address: {address}</p>
    <p>price: {price}</p>
  </div>
)
//wrapper ui component relying on storedPosts property
//that will get connected to global state posts later on
const PostBoard = ({storedPosts}) => (
  <div>
    {storedPosts.map((post, key) => <Post key={key} {...post} />)}
  </div>
)
//connect storedPosts to global state posts
const mapStateToProps = ({posts}) => ({storedPosts: posts}),
      PostBoardComponent = connect(mapStateToProps)(PostBoard)
//render Redux Provider
render (
  <Provider store={store}>
    <PostBoardComponent />
  </Provider>,
  document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.1.3/react-redux.min.js"></script><div id="root"></div>