简体   繁体   中英

Able to get the updated state from redux store but not able to access the objects inside the updated state from the receiver component

I'm creating a simple book list application using react and managing the state using redux. I've only 2 components that deal with the state, the input component dispatches the action and payload, while the output component should get the updated state data. Using the useSelector() hook inside the output component, I can see that the state is updated, however, when I try to access the array of objects and a length property, I get 'cannot read properties of undefined'. Please let me know what did I miss here.

Here is my code for Input Component

import React, { useState } from "react";
import { useDispatch } from "react-redux";
import styles from "./Input.module.css";

const Input = () => {
  const dispatch = useDispatch();

  const [bookObject, setBookObject] = useState({
    bookName: "",
    authorName: "",
  });

  const inputChangeHandler = (e) => {
    if (e.target.id === "bookName" || e.target.id === "authorName") {
      setBookObject({
        bookName: document.getElementById("bookName").value,
        authorName: document.getElementById("authorName").value,
      });
    }
  };

  const submitHandler = (e) => {
    if (bookObject.bookName !== "" && bookObject.authorName !== "") {
      dispatch({
        type: "GET_INPUT",
        payload: {
          name: bookObject.bookName,
          author: bookObject.authorName,
          id: Math.random(),
        },
      });
      setBookObject({ bookName: "", authorName: "" });
    } else {
      alert("Enter valid Details");
    }
    e.preventDefault();
  };

  return (
    <form className={styles.form} onSubmit={submitHandler}>
      <div>
        <label>Book's Name</label>
        <input
          id="bookName"
          type="text"
          placeholder="Enter the book's name"
          onChange={inputChangeHandler}
          value={bookObject.bookName}
        />
      </div>
      <div>
        <label>Author's Name</label>
        <input
          id="authorName"
          type="text"
          placeholder="Enter the Author's name"
          onChange={inputChangeHandler}
          value={bookObject.authorName}
        />
      </div>
      <button>Submit</button>
    </form>
  );
};

export default Input;

Here is the code of the Output Component

import React, { Fragment } from "react";
import styles from "./Output.module.css";
import { useSelector } from "react-redux";

const Output = () => {
  
  const outputState = useSelector((state) => state);
  const length = outputState.length
  const outputObj = outputState.outputObj

  return (
    <Fragment>
      {length !== undefined ? (
        <div className={styles.div}>
          <h4>Book List</h4>
          <ul>
            {outputObj.map((book) => (
              <li key={book.id}>
                {book.name}, written by {book.author}
              </li>
            ))}
          </ul>
        </div>
      ) : (
        <h4>The Book List is empty</h4>
      )}
    </Fragment>
  );
};

When I console log the outputState, I get a proper object with outputObj array and a length property, but when I try to access outputState.outputObj or outputState.length, I get the error mentioned. I've also tried using two useSelectors each to get the data separately, but in vain.

Here is the code of reducer

import { createStore } from "redux";

const defaultState = {
  outputObj: [],
  length: undefined,
};

const bookListReducer = (state = defaultState, action) => {
  if (action.type === "GET_INPUT") {
    state.outputObj = [...state.outputObj, action.payload];
    return {
      outputObj: state.outputObj,
      length: state.outputObj.length,
    };
  }
};

const store = createStore(bookListReducer);

export default store;

If there was no action, or your action's type was not "GET_INPUT" your reducer will return undefined, therefore the state will be flushed. Update your code as follows.

const bookListReducer = (state = defaultState, action) => {
  if (action.type === "GET_INPUT") {
    state.outputObj = [...state.outputObj, action.payload];
    return {
      outputObj: state.outputObj,
      length: state.outputObj.length,
    };
  }

  return state; // <- HERE
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM