1

I have an array "movies" of objects like this:

{
 id: "some id",
 title: "some title",
 actors: []
}

As you can see, the actors array stays empty, because I don't add actors while I am adding a movie. I want to add actors later on, while being on http://localhost:3000/movies/<movieId> . I do this by this Form. Im just selecting a actor, from already existing lists of actors.

const PostForm = ({ addActorToMovie, movie, actors, history }, props) => {
  const handleSubmit = (values) => {
    addActorToMovie(values);
    // history.push(`/movies/${movie.id}`);
  };
  let actorsList =
    actors.length > 0 &&
    actors.map((item, i) => {
      return (
        <option value={`${item.firstName}, ${item.lastName}`}>
          {item.firstName + item.lastName}{" "}
        </option>
      );
    });

  return (
    <div>
      <h3>Add Actor</h3>
      <Formik
        initialValues={{
          actor: "",
        }}
        onSubmit={(values) => handleSubmit(values)}
        enableReinitialize={true}
      >
        <Form>
          <Field name="actor" component="select">
            <option value="null"> </option>
            {actorsList}
          </Field>
          <button type="submit">Zatwierdz</button>
        </Form>
      </Formik>
    </div>
  );
};

const mapStateToProps = (state, props) => {
  return {
    movie: state.movie,
    actors: state.actors,
  };
};

const mapDispatchToProps = {
  addActorToMovie,
};

export default withRouter(
  connect(mapStateToProps, mapDispatchToProps)(PostForm)
);

The form works. Although instead of adding value to my actors array. It creates a new object under movies array which looks like this:

actors: {actor: 'Some actor name'}

My reducers looks like this. Probably this is the source of the problem, but I don't really know how to do this.

export const movieReducer = (state = [], action) => {
  switch (action.type) {
    case "MOVIE_ADD":
      return [...state, action.payload];
    case "MOVIE_DELETE":
      return [...state.filter((el) => el.id !== action.payload.id)];
    case "MOVIEACTOR_ADD":
      return {
        ...state,
        actors: action.payload
      };
    default:
      return state;
  }
};

What I want to do is of course push the actor which i enter in my Formik to an array of specified movie.

1
  • You mentioned a movies array, we need to see the state shape in the reducer to correctly copy the movies array, and in this case the ADD_ACTOR_TO_MOVIE should include which movie it's adding an actor to. We should also see the UI component that is dispatching the action as well. Commented Nov 24, 2021 at 23:26

1 Answer 1

1

Instead of declaring a new actors property that is only the payload, you want to append it to the existing actors array. However, you will first need to know which movie object you are updating, so this also needs to be sent in the action payload.

Update the submit handler to send both the movie id and the actor to be added.

const handleSubmit = ({ actor }) => {
  addActorToMovie({
    movieId: movie.id,
    actor,
  });
};

Update the reducer case to map the movies array, which appears to be state in movieReducer. Shallow copy the movies state array, and for the matching movie id, shallow copy and append the actor to the actors array.

case "MOVIE_ACTOR_ADD":
  const { actor, movieId } = action.payload;
  return state.map(movie => movie.id === movieId
    ? {
      ...movie,          // <-- shallow copy movie object
      actors: [
        ...movie.actors, // <-- shallow copy existing array
        actor            // <-- append new actor payload
      ],
    }
    : movie
  );

When adding a movie to state, ensure the actors array property exists. If you aren't passing it the MOVIE_ADD action payload then handle it in the reducer when adding a movie.

case "MOVIE_ADD":
  return [
    ...state,
    { ...action.payload, actors: [] },
  ];
Sign up to request clarification or add additional context in comments.

3 Comments

Warning: An unhandled error was caught from submitForm() TypeError: state.actors is not iterable.
Well, i belive that your answer is correct, but seems that I am having error somewhere else too
Thank you, I did not belive that you will come across the working answers with the small amout of data i provided. TY !

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.