Hansel Wong
Hansel Wong

Reputation: 1

React component not re-rendering when updating Redux store

i am trying to create a toggle for favouriting a Card Component so that it renders in my Favorites.js component. I am using Redux to store the state but when i dispatch an action to add or remove them from the store the components are not rendering. I think i am mutating the state of the array.

Here's the reducer:

 export function rootReducer(state = [], action) {


      switch(action.type) {
        case 'ADD_FAVORITE':
        return state.concat(action.data);
        case 'SUB_FAVORITE':
        return state.filter(state => state.name !== action.data.name);
        default:
          return state;
      }
    }

I tried using Object.assign to a create a new Array but since the data passed into my state is in a array itself, i can't use store.getState() to map them into my component. The array becomes nested within itself.

This is the function that i am running onClick to dispatch the actions:

toggleFavorites(e) {
    if
    (store.getState().includes(this.props.data))
  {
    console.log(this.props.data.name + ' removed from favorites');
    store.dispatch({type: 'SUB_FAVORITE', data: this.props.data});

  }
    else{

    console.log(this.props.data.name + ' added to favorites');
    store.dispatch({type: 'ADD_FAVORITE', data: this.props.data});
  }

This.props.data is passed from referencing an array in a JSON object and mapping it into my Card Component

Here's the Card Component that i am rendering:

render() {
    let {name, description, url , screenshot} = this.props.data;
    return (
      <div className="cardComponent">
        <div className="CTA-container">
          <div className="CTA-wrapper">
            <div onClick={() => this.toggleFavorites(this.props.data)}className="CTA-icon"><IconComponent icon="favorite"/></div>
            <a href={url} className="CTA-icon" target="_blank"><IconComponent icon="link"/></a>
        </div>
      </div>
      <img src={screenshot} alt="" className="cardComponent_img"/>
      <a href={url} className="cardComponent_name" target="_blank">{name}</a>
      <p className="cardComponent_description">{description}</p>

      </div>

I am rendering these Card Components into the Favorites.js Component like this:

class Favorites extends Component {

  constructor(props) {
    super(props);
   }
    render() {

        let cardComps = store.getState().map(data => {
          return (
            <CardComponent data = {data} />
          )
        })

        return (

          <div>

          <div className="array-component">{cardComps}</div>

export default Favorites;

I am fairly new to React and Redux so i am not sure if i did something wrong when setting up the components. I just need the component to re-render when the user adds or remove it from their Favourites.

Upvotes: 0

Views: 104

Answers (2)

Anshul Bansal
Anshul Bansal

Reputation: 1893

You also need to use the connect method fro react-redux library to listen to the store updates. For reference I have included the code.

In Reducer

switch(action.type) {
    case 'ADD_FAVORITE':
        return [...state,action.data];
    case 'SUB_FAVORITE':
        return [...state.filter(state => state.name !== action.data.name)]
    default:
        return state;
}

In Favorites.js Components

import { connect } from 'react-redux';

class Favorites extends Component {
    constructor(props) {
        super(props);
        this.state = {
            storeData: []
        }
    }
    componentWillReceiveProps(nextProps){
        if(nextProps.storeData !== this.state.storeData){
            this.setState({
                storeData: nextProps.storeData
            })
        }
    }
    render() {
        const { storeData } = this.state;
        let cardComps = storeData.map(data => {
            return <CardComponent data = {data} />;
        })
        return (
            <div className="array-component">{cardComps}</div>;
        );
    }
}

const mapStateToProps = state => {
    return {
        storeData: state
    };
};

const connectedFavorites = connect(mapStateToProps)(Favorites);

export default connectedFavorites;

Upvotes: 0

RIYAJ KHAN
RIYAJ KHAN

Reputation: 15290

Redux do shallow comparison of reference for updated state and based on that decide whether to update component or not.

Both Array#concat and Array#filter return new array with same referenced elements.So,state comparison return false and no rendering happening.

Assuming action.data is a one dimensional array. This should work.

switch(action.type) {
    case 'ADD_FAVORITE':
       return [...state,action.data];
    case 'SUB_FAVORITE':
       return [...state.filter(state => state.name !== action.data.name)]
    default:
       return state;
 }

Upvotes: 2

Related Questions