简体   繁体   中英

How to update redux state using onChange with React Redux

I'm using React Redux and want to be able to change the title and description of a post, using the onChange method. When only using React the way you would do this is that you keep an useState which you change whenever a change occurs, but I can't seem to get it to work with using redux in react. Instead of the state changing the original title, and description remains and cannot be changed.

From what I have read the basic idea is to have a listener on the input (onChange, usually) and have that fire a redux action. You then have the action tell the reducer to make the change to the store.

I have tried doing this, but could make it work correctly. What am I doing wrong and how do you solve it? I'm also wondering how do I specify that I want to change either title or description when using onChange, or do I simply send everything in post each time a change occurs?

This is what the redux state looks like when entering a post:

{
  auth: {
    isSignedIn: true,
    user: {
      id: '624481f22566374c138cf974',
      username: 'obiwan',}
  },
  posts: {
    '62448632b87b223847eaafde': {
      _id: '62448632b87b223847eaafde',
      title: 'hellothere',
      desc: 'its been a long time since I heard that name...',
      username: 'vorbrodt',
      email: 'example@gmail.com',
      categories: [],
      createdAt: '2022-03-30T16:32:50.158Z',
      updatedAt: '2022-03-30T16:32:50.158Z',
      __v: 0
    }
  },
}

Here is where the onChange happens. Post.js

import { getPostById, editPost } from "../actions";

const Post = ({ getPostById, editPost, username }) => {
  const [updateMode, setUpdateMode] = useState(false);
  let { id } = useParams();
  let post = useSelector((state) => state.posts[id]);


  const handleInputChange = (e) => {
    try {
      editPost(e.target.value);
    } catch (err) {}
  };

  return (
    <div className="post">
      <div className="post-wrapper">
      {updateMode ? (
        <input
          type="text"
          value={post.title}
          className="post-title-input"
          autoFocus
          onChange={(e) => handleInputChange(e)}
        />
      ) : (
        <h1 className="post-title">
          {post.title}
        </h1>
      )}
      <div className="desc-area">
        {updateMode ? (
          <textarea
            className="post-desc-input"
            value={post.desc}
            onChange={(e) => handleInputChange(e)}
          />
        ) : (
          <p className="post-desc">{post.desc}</p>
        )}
      </div>
    </div>
    </div>
  );
};

const mapStateToProps = (state) => {
  return { username: state.auth.user.username }; 
};

export default connect(mapStateToProps, { getPostById, editPost })(Post);

Here is the action creator:

//edit post in redux state
const editPost = (postValues) => (dispatch) => {
  dispatch({ type: EDIT_POST, payload: postValues });
};

And here is the reducer which is suppose to change the state. postReducer.js

import _ from "lodash";

import { GET_POSTS, GET_POST, CREATE_POST, EDIT_POST } from "../actions/types";

function postReducer(state = {}, action) {
  switch (action.type) {
    case GET_POSTS:
      return { ...state, ..._.mapKeys(action.payload, "_id") };
    case GET_POST:
      return { ...state, [action.payload._id]: action.payload };
    case CREATE_POST:
      return { ...state, [action.payload._id]: action.payload };
    case EDIT_POST:
      //here the change should occur, not sure how to specify if title or desc should 
      //change
      return { ...state, [action.payload._id]: action.payload };
    default:
      return state;
  }
}

export default postReducer;

Hey there something like this should be of help

const handleInputChange = (e, key, id) => {
    try {
      editPost({ [key]: e.target.value, id });
    } catch (err) {}
  };

Usage

           <textarea
            className="post-desc-input"
            value={post.desc}
            onChange={(e) => handleInputChange(e, "title", post.id)}
          />

action

const editPost = (postValues) => (dispatch) => {
  dispatch({ type: EDIT_POST, payload: postValues });
};

Reducer

    case EDIT_POST:
//here we destructure the id and return the data without the id cause we //need it below
const {id, ...newData} = action.payload
const indexToUpdate = state.posts.find(post => post.id === id)
const newPostsData = [...state.posts]

//Here we update the actual object and its property that is in the state at //the specific value
newPostsData[indexToUpdate] = {...newPostData[indexToUpdate], {...newData}
          return { ...state, posts: newPostsData};

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