0

i am currently React SPA application based on react-redux. in the reducer.js, I have two main states, which is mylist and recommendations. I have attached two picture of actually applicaion. there are two pages. first one is Home page which there are three initial recommendations of movies. under each movie there is a add button, which once you clicked the botton and the expectation is selected movie will be removed and will be added to second pages which is a mylist page.

on the mylist page, there will be three initial movie. there is a remove button underneath each movie, once i have clicked remove button, expectation is the selected movie is removed and will be added back to home page.

rightnow, i have implemented the add button, which once i clicked add button, the selected movie will be removed and will be add to mylist page.

the problem is in the mylist page once i clicked remove. the selected movie is removed but its not added to the home page.

Home.js

class Home extends Component {
  handleClick = id => {
    this.props.addToList(id);
    this.props.removeFromRecom(id);
  };
  render() {
    let addedRecom1 = this.props.addedRecom.map(item => {
      return (
        <div key={item.id} style={{ float: "left", marginLeft: "20px" }}>
          <Image webP={item.img}></Image>
          <p style={{ marginLeft: "44px" }}>{item.title}</p>
          <button
            to="/"
            onClick={() => this.handleClick(item.id)}
            style={{
              marginLeft: "53px",
              paddingLeft: "10px",
              paddingRight: "10px",
              paddingTop: "0px",
              marginTop: "0px",
              marginBottom: "20px"
            }}
          >
            add
          </button>
        </div>
      );
    });
    return (
      <div>
        <div>
          <NavLink to="/myList" style={{ textDecoration: "none" }}>
            <a
              style={{
                marginLeft: "378px",
                fontFamily: "Arial Black",
                color: "black",
                border: "solid 1px",
                backgroundColor: "orange",
                paddingLeft: "35px",
                paddingRight: "20px"
              }}
            >
              <i
                class="fa fa-plus"
                style={{ paddingRight: "10px", paddingLeft: "5px" }}
              ></i>
              My list
            </a>
          </NavLink>
          <p style={{ marginTop: "20px", marginLeft: "20px" }}>
            Recommendations
          </p>
        </div>
        <div>
          {this.props.recommendations.map(item => {
            return (
              <div key={item.id} style={{ float: "left", marginLeft: "20px" }}>
                <Image webP={item.img}></Image>
                <p style={{ marginLeft: "44px" }}>{item.title}</p>
                <button
                  to="/"
                  onClick={() => this.handleClick(item.id)}
                  style={{
                    marginLeft: "53px",
                    paddingLeft: "10px",
                    paddingRight: "10px",
                    paddingTop: "0px",
                    marginTop: "0px",
                    marginBottom: "20px"
                  }}
                >
                  add
                </button>
              </div>
            );
          })}
        </div>
        {addedRecom1}
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    addedRecom: state.addedRecom,
    recommendations: state.recommendations
  };
};

const mapDispatchToProps = dispatch => {
  return {
    addToList: id => {
      dispatch(addToList(id));
    },
    removeFromRecom: id => {
      dispatch(removeFromRecom(id));
    }
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Home);

MyList.js

class MyList extends Component {
  handleRemoveMovie = id => {
    this.props.removeFromList(id);
    this.props.addToRecom(id);
  };
  render() {
    let addedMovies = this.props.addedMovies.map(item => {
      return (
        <div key={item.id} style={{ float: "left", marginLeft: "20px" }}>
          <Image webP={item.img}></Image>
          <p style={{ marginLeft: "44px" }}>{item.title}</p>
          <button
            to="myList"
            onClick={() => {
              this.handleRemoveMovie(item.id);
            }}
            style={{
              marginLeft: "53px",
              paddingLeft: "10px",
              paddingRight: "10px",
              paddingTop: "0px",
              marginTop: "0px",
              marginBottom: "20px"
            }}
          >
            remove
          </button>
        </div>
      );
    });
    return (
      <div>
        <div>
          <NavLink to="/" style={{ textDecoration: "none" }}>
            <a
              style={{
                marginLeft: "317px",
                fontFamily: "Arial Black",
                color: "black",
                border: "solid 1px",
                backgroundColor: "orange",
                paddingLeft: "28px",
                paddingRight: "20px"
              }}
            >
              <i
                class="fa fa-hand-o-left"
                style={{ paddingRight: "10px", paddingLeft: "5px" }}
              ></i>
              back to Home
            </a>
          </NavLink>
          <p style={{ marginTop: "20px", marginLeft: "20px" }}>My Lists</p>
        </div>
        <div>
          {this.props.mylist.map(item => {
            return (
              <div key={item.id} style={{ float: "left", marginLeft: "20px" }}>
                <Image webP={item.img}></Image>
                <p style={{ marginLeft: "44px" }}>{item.title}</p>
                <button
                  to="myList"
                  onClick={() => {
                    this.handleRemoveMovie(item.id);
                  }}
                  style={{
                    marginLeft: "53px",
                    paddingLeft: "10px",
                    paddingRight: "10px",
                    paddingTop: "0px",
                    marginTop: "0px",
                    marginBottom: "20px"
                  }}
                >
                  remove
                </button>
              </div>
            );
          })}
        </div>
        {addedMovies}
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    addedMovies: state.addedMovies,
    mylist: state.mylist
  };
};

const mapDispatchToProps = dispatch => {
  return {
    removeFromList: id => {
      dispatch(removeFromList(id));
    },
    addToRecom: id => {
      dispatch(addToRecom(id));
    }
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(MyList);

reducer.js

const initialState = {
  mylist: [
    {
      title: "Futurama",
      id: 1,
      img: "http://cdn1.nflximg.net/webp/7621/3787621.webp"
    },
    {
      title: "The Interview",
      id: 2,
      img: "http://cdn1.nflximg.net/webp/1381/11971381.webp"
    },
    {
      title: "Gilmore Girls",
      id: 3,
      img: "http://cdn1.nflximg.net/webp/7451/11317451.webp"
    }
  ],
  recommendations: [
    {
      title: "Family Guy",
      id: 4,
      img: "http://cdn5.nflximg.net/webp/5815/2515815.webp"
    },
    {
      title: "The Croods",
      id: 5,
      img: "http://cdn3.nflximg.net/webp/2353/3862353.webp"
    },
    {
      title: "Friends",
      id: 6,
      img: "http://cdn0.nflximg.net/webp/3200/9163200.webp"
    }
  ],
  addedMovies: [],
  addedRecom: []
};

const reducer = (state = initialState, action) => {
  if (action.type === REMOVE_FROM_RECOM) {
    let Recom = state.recommendations.filter(item => item.id !== action.id);
    return {
      ...state,
      recommendations: Recom
    };
  }

  if (action.type === ADD_TO_LIST) {
    let addedMovie = state.recommendations.find(item => item.id === action.id);
    let existed_movie = state.mylist;
    if (existed_movie) {
      return {
        ...state,
        addedMovies: [...state.addedMovies, addedMovie]
      };
    }
  }

  if (action.type === ADD_TO_RECOM) {
    let add_recom = state.mylist.find(item => item.id === action.id);
    let current_recom = state.recommendations;
    if (current_recom) {
      return {
        ...state,
        addedRecom: [...state.addedRecom, add_recom]
      };
    }
  }

  if (action.type === REMOVE_FROM_LIST) {
    let removedMovie = state.mylist.find(item => item.id === action.id);
    let newMovie = state.addedMovies.filter(item => item.id !== action.id);
    return {
      ...state,
      addedMovies: newMovie
    };
  } else {
    return state;
  }
};[![enter image description here][1]][1]

export default reducer;


TypeError: Cannot read property 'id' of undefined
(anonymous function)
src/Home.js:17

  14 | render() {
  15 |   let addedRecom1 = this.props.addedRecom.map(item => {
  16 |     return (
> 17 |       <div key={item.id} style={{ float: "left", marginLeft: "20px" }}>
     | ^  18 |         <Image webP={item.img}></Image>
  19 |         <p style={{ marginLeft: "44px" }}>{item.title}</p>
  20 |         <button

[![enter image description here][1]][1] enter image description here

6
  • 3
    Let's make an update to your question. Let's edit it to clearly state what the problem is, what result you have, and what result you are expecting. Only include the relevant part of the code. This makes it easier to understand your issue and propose a solution. Commented Jan 5, 2020 at 2:09
  • I suspect that the issue is here let add_recom = state.mylist.find(item => item.id === action.id); If add_recom is undefined, it may throw that error. Commented Jan 5, 2020 at 2:20
  • I have edit again, sorry for the confusion, hope is clear this time @Ibu Commented Jan 5, 2020 at 2:20
  • thanks for the comment @Neil Chowdhury could that be something wrong about state.mylist? Commented Jan 5, 2020 at 2:35
  • use redux devtools and watch the store, or run console.log(state.mylist) before where you're getting the error to see what the problem is Commented Jan 5, 2020 at 4:06

1 Answer 1

1

In general you should have only two lists, one for recommendations and one for myList, and two reducers that handle deletion and addition of items from myList:

const initialState = {
    myList: [
        {
            title: 'Futurama',
            id: 1,
            img: 'http://cdn1.nflximg.net/webp/7621/3787621.webp'
        },
        {
            title: 'The Interview',
            id: 2,
            img: 'http://cdn1.nflximg.net/webp/1381/11971381.webp'
        },
        {
            title: 'Gilmore Girls',
            id: 3,
            img: 'http://cdn1.nflximg.net/webp/7451/11317451.webp'
        }
    ],
    recommendations: [
        {
            title: 'Family Guy',
            id: 4,
            img: 'http://cdn5.nflximg.net/webp/5815/2515815.webp'
        },
        {
            title: 'The Croods',
            id: 5,
            img: 'http://cdn3.nflximg.net/webp/2353/3862353.webp'
        },
        {
            title: 'Friends',
            id: 6,
            img: 'http://cdn0.nflximg.net/webp/3200/9163200.webp'
        }
    ]
};

Each reducer is incharge of updating both recommendations and myList upon deletion/addition of a movie:

const reducer = (state = initialState, action) => {
    if (action.type === 'ADD_TO_LIST') {
        let addToMyList = state.recommendations.find(item => item.id === action.id);
        return {
            ...state,
            myList: [ ...state.myList, addToMyList ],
            recommendations: state.recommendations.filter(item => item.id !== action.id)
        };
    }

    if (action.type === 'REMOVE_FROM_LIST') {
        let removedItem = state.myList.find(item => item.id === action.id);
        return {
            ...state,
            myList: state.myList.filter(item => item.id !== action.id),
            recommendations: [ ...state.recommendations, removedItem ]
        };
    } else {
        return state;
    }
};

export default reducer;

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.