tomrlh
tomrlh

Reputation: 1066

React updates the state but not the component with Redux

I have a blog application that I want to sort my posts by votes or title, so I have this buttons for sorting:

<Button size='mini' onClick={() => {this.props.sortByVotes()}}>
    Votes
</Button>
<Button size='mini' onClick={() => {this.props.sortByTitle()}}>
    Title
</Button>

The actions is like this:

export const sortByVotes = posts => ({ type: SORT_BY_VOTES })

export const sortByTitle = posts => ({ type: SORT_BY_TITLE })

And reducer is as it follows:

case SORT_BY_VOTES:
    return {
        ...state,
        posts: state.posts.sort((a, b) => b.voteScore - a.voteScore)
    }
case SORT_BY_TITLE:
    return {
        ...state,
        posts: state.posts.sort((a, b) => {
            if (a.title > b.title) return 1
            if (a.title < b.title)return -1
            return 0
        })
    }

Finally, in the Main.js view I get posts in componentDidMount and shows it like this:

<Item.Group divided>
    {this.props.posts.map((p, idx) =>
        <PostSmall key={idx}
            id={p.id}
            title={p.title}
            body={p.body}
            category={p.category}
            voteScore={p.voteScore}
        />
    )}
</Item.Group>

Still in Main.js, I map the posts from state like this:

function mapStateToProps(state) {
    return {
        posts: state.posts.posts,
        categories: state.categories.categories
    }
}

As you can see, nothing special here.

The problem is: the state is update as expected, but view not.

Ti'll now I have not figured out how to solve it, and why this is happening.

Any help will be grateful.

Upvotes: 0

Views: 54

Answers (2)

Shanti Swarup Tunga
Shanti Swarup Tunga

Reputation: 641

The object posts is not changing hence React is not rendering the component.

I have added a work around fix.

reducers/posts.js

case SORT_BY_VOTES:
			const posts = Object.assign({},{posts:state.posts.sort((a, b) => b.voteScore - a.voteScore
			)})
			return Object.assign ({}, state, posts);

In Main.js

import React from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { Container, Divider, Grid, Item } from 'semantic-ui-react'
import Categories from '../components/Categories'
import PostSmall from '../components/PostSmall'
import PostsSorter from '../components/PostsSorter'

import { fetchPosts } from '../actions/posts'
import { fetchCategories } from '../actions/categories'

class Main extends React.Component {

	render() {
		const posts = this.props.posts ? this.props.posts.posts || [] : [];
		console.log('render')
		return (
			<Container>
				<Grid columns='equal'>
					<Grid.Column>
						<PostsSorter/>
						<Divider/>
						<Categories categories={this.props.categories}/>
					</Grid.Column>
					<Grid.Column width={10}>
						<Item.Group divided>
							{posts.map((p, idx) =>
								<PostSmall key={idx} post={p}/>
							)}
						</Item.Group>
					</Grid.Column>
				</Grid>
			</Container>
		);
	}



	componentDidMount() {
		this.props.getPosts()
		this.props.getCategories()
	}
}



Main.propTypes = {
	posts: PropTypes.array,
	categories: PropTypes.array
}

Main.defaultProps = {
	posts: [],
	categories: []
}



function mapStateToProps(state) {
	console.log(state);
	return {
		posts: state.posts,
		categories: state.categories.categories
	}
}

function mapDispatchToProps(dispatch) {
	return {
		getPosts: () => dispatch(fetchPosts()),
		getCategories: () => dispatch(fetchCategories())
	}
}

export default connect(mapStateToProps, mapDispatchToProps)(Main)

But you have to refactor the code in order to make the component pure and connect the redux state only to view.

Upvotes: 1

arunmmanoharan
arunmmanoharan

Reputation: 2675

Your action doesnt send a payload. Are you initiating an API call in actions to send to the reducer? In your reducer, you need to capture the payload from actions and then update the state.

Actions: actions.tsx Reducers: reducers.tsx

So, the common workflow is to have a parameter in actions and then modify the default state in the reducer. See a sample above for reference.

Hope this helps.

Upvotes: 0

Related Questions