JavaScript React Redux: Cannot Delete Item on Web Page Without Refreshing First

我们两清 提交于 2019-12-24 22:37:24

问题


I have the current web page below and want to delete a user when I click on the red 'x' button at the top of the card.

Currently, after I click the 'x' delete button, nothing happens. After I refresh the page, the user will be removed from my webpage. But I want this to happen without needing a refresh at all.

Sample Web Page Render:

Back-end Route:

To achieve this, I tried the following:

Setup back-end route:

    const router = require('express').Router()
    const {User} = require('../db/models')
    module.exports = router
    const {isUser, isAdmin} = require('../checks')
    // 8080/api/users/:userId

    router.delete('/:userId', isAdmin, async (req, res, next) => {
      let userId = req.params.userId

      try {
        await User.destroy({
          where: {
            id: userId
          }
        })
        res.status(204)
      } catch (err) {
        next(err)
      }
    })

Setup redux store and thunk:

    import axios from 'axios'

    // ACTION TYPES

    const SET_USERS = 'SET_USERS'
    const DELETE_USER = 'DELETE_USER'

    // ACTION CREATORS

    export const setUsers = users => ({
      type: SET_USERS,
      users: users
    })

    export const deleteUser = delUserId => ({
      type: DELETE_USER,
      delUserId: delUserId
    })

    // DOLLAR HELPER FOR CENTS FIELD

    // export const toDollars = cents => {
    //   return `$${(cents / 100).toFixed(2)}`
    // }

    // THUNK CREATORS

    export const getUsers = () => async dispatch => {
      try {
        const {data} = await axios.get('/api/users')
        dispatch(setUsers(data))
        console.log('getUsersThunk DATA ARRAY', data)
      } catch (err) {
        console.error(err)
      }
    }

    export const deleteUserThunk = delUserId => async dispatch => {
      try {
        const response = await axios.delete(`/api/users/${delUserId}`)
        const deleteUserId = response.data

        dispatch(deleteUser(deleteUserId))
        console.log('getUsersThunk DELETE', deleteUserId)
      } catch (err) {
        console.error(err)
      }
    }

    // REDUCER

    // INITIAL STATE

    const allUsers = []

    export default function(state = allUsers, action) {
      switch (action.type) {
        case SET_USERS:
          return action.users
        case DELETE_USER: {
          let userRemovalArray = state.filter(user => user.id !== action.delUserId)
          return userRemovalArray
        }
        default:
          return state
      }
    }

Build front-end component that calls 'deleteUserThunk'

import React from 'react'
import {connect} from 'react-redux'
import {getUsers, deleteUserThunk} from '../store/allUsers'
import {updateUserThunk, fetchSingleUser} from '../store/singleUser'
// Status Filter import BeerFilter from './BeerFilter'
import Card from 'react-bootstrap/Card'
import Button from 'react-bootstrap/Button'
import {UncontrolledCollapse} from 'reactstrap'

export class AllUsers extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      showForm: false,
      stat: ''
    }
    this.clickHandlerOne = this.clickHandlerOne.bind(this)
    this.handleChange = this.handleChange.bind(this)
    this.handleSubmit = this.handleSubmit.bind(this)
  }

  componentDidMount() {
    try {
      this.props.fetchInitialUsers()
    } catch (error) {
      console.error(error)
    }
  }

  clickHandlerOne() {
    let hidden = this.state.showForm
    this.setState({
      showForm: !hidden
    })
  }

  handleChange(event) {
    //console.log('event.target', event.target)
    this.setState({
      [event.target.name]: event.target.value
    })
  }

  async handleSubmit(userId) {
    event.preventDefault()

    const updatedUser = {
      id: userId,
      isAdmin: this.state.stat
    }

    // console.log('UPDATE USER', updatedUser)

    await this.props.updateUserThunk(updatedUser)
    this.props.fetchInitialUsers()
  }

  render() {
    const users = this.props.users
    // console.log('PROPS', this.props)
    console.log('USERS', this.props.users)

    return (
      <div>
        {/* <div className="options">
          <select onChange={this.handleChange}>
            <option value="">Sort By...</option>
            <option value="priceHighToLow">Price (high to low)</option>
            <option value="priceLowToHigh">Price (low to high)</option>
            <option value="name">Name</option>
          </select>

          <BeerFilter />
          </div> */}

        <div className="flex-cards">
          {users.map(user => (
            <Card style={{width: '18rem'}} key={user.id}>
              {/* delete thunk */}
              <div>
                <Button
                  id={`delete${user.id}`}
                  variant="danger"
                  onClick={() => this.props.deleteUserThunk(user.id)}
                >
                  X
                </Button>
              </div>

              <Card.Body>
                <Card.Title>User Id: {user.id}</Card.Title>
                <Card.Text>
                  <div>
                    <ul>
                      <li>
                        <div className="highlight">
                          <img src={user.imageUrl} />
                        </div>
                        <div className="details">
                          <p>Username: {user.username}</p>
                          <p>User Email: {user.email}</p>
                          <p>Admin Status: {user.isAdmin ? 'true' : 'false'}</p>
                          <p>
                            Created Date:{' '}
                            {new Intl.DateTimeFormat('en-GB', {
                              month: 'short',
                              day: '2-digit',
                              year: 'numeric'
                            }).format(new Date(user.createdAt))}
                          </p>
                          <p />
                          <Button
                            id={`user${user.id}`}
                            onClick={() => {
                              this.clickHandlerOne()
                            }}
                            variant="outline-info"
                          >
                            Admin Status Toggle
                          </Button>
                          <UncontrolledCollapse toggler={`#user${user.id}`}>
                            <form onSubmit={() => this.handleSubmit(user.id)}>
                              <div>
                                <span>
                                  <select
                                    name="stat"
                                    value={this.state.isAdmin}
                                    onChange={this.handleChange}
                                  >
                                    <option value="">user isAdmin?</option>
                                    <option value="true">true</option>
                                    <option value="false">false</option>
                                  </select>
                                </span>

                                <div>
                                  {/* */}
                                  <button type="submit">Submit</button>
                                </div>
                              </div>
                            </form>
                          </UncontrolledCollapse>
                        </div>
                      </li>
                    </ul>
                  </div>
                </Card.Text>
              </Card.Body>
            </Card>
          ))}
        </div>
      </div>
    )
  }
}

const mapStateToProps = state => {
  return {
    users: state.allUsers
  }
}

const mapDispatchToProps = dispatch => {
  return {
    loadSingleUser: id => dispatch(fetchSingleUser(id)),
    updateUserThunk: updatedUser => dispatch(updateUserThunk(updatedUser)),
    //getSortedBeers: (sortBy, beers) => dispatch(sortBeers(sortBy, beers)),
    fetchInitialUsers: () => dispatch(getUsers()),
    deleteUserThunk: userId => dispatch(deleteUserThunk(userId))
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(AllUsers)

With my code above, when I click on the red 'x' button nothing happens. I have to hit the refresh button for my now deleted user to be removed from my webpage.

How can I have the user removed from my current view without having to hit refresh?


回答1:


This isn't a complete answer, but there's definitely a problem here:

const response = await axios.delete(`/api/users/${delUserId}`)

If you look at the screenshot you provided of the error in the web console, it's showing undefined where delUserId should be. So somewhere along the line between the click on the 'X' and the line above, you aren't passing the user ID correctly.




回答2:


Here, as you are using mapDispatchToProps in your component "AllUsers"

your deleteUserThunk(in THUNK CREATORS) is assigned to deleteUserThunk(in your component "AllUsers")

hence, you need to call your THUNK CREATEORS function by calling the component function which is assigned in mapDispatchToProps

You have to call it in the following way

onClick={() => this.props.deleteUserThunk(user.id)}

This will pass your user.id to deleteUserThunk(in your component "AllUsers") to deleteUserThunk(in THUNK CREATORS)

As per your comments.. Firstly, you have to remove it from componentDidMount() because, you should not run your delete function when your component is mounted.

Secondly, if your reducer is updated, then your browser will update without any refresh. Try checking the parameters which are passed into DELETE_USER

my suggestion would be: in your function deleteUserThunk (in THUNK CREATORS) replace dispatch(deleteUser(deleteUserId)) with dispatch(deleteUser(delUserId))



来源:https://stackoverflow.com/questions/58049013/javascript-react-redux-cannot-delete-item-on-web-page-without-refreshing-first

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!