首页 > 解决方案 > React Redux - 具有互斥选项的选择下拉列表

问题描述

我在这个问题上摸不着头脑。而且我发现这也不容易解释。我将尽我所能:

我有一个 html 表格,每一行都有一个图像,除其他元素外,还有一个带有前 10 个列表的选择下拉列表,用于对图像进行排名。当用户选择排名时,数据库会相应更新 -> 当前图片前 10 排名保存在图片条目中,之前继承该位置的图片的排名更新为“null”。(这已经在工作了 -> 所以如果我重新加载页面,一切都会好起来的)。我无法实现的是,我从数据库接收到的更新图像数组来更新状态(或道具),因此之前继承了排名的图像的选定选项值。这是我的ImageList组件(重要部分):

class ImageList extends Component {


constructor(props) {
    super(props)
    this.state = {
      project: [],
      description: '',
      name: '',
      values: [],
      value: '',
      positions: props.positions
    }
  }

  updatePosition = (projectId, projectName, imageId, imgName, i, e) => {

    this.props.setGridPosition(
      projectId,
      projectName,
      imageId,
      imgName,
      e.target.value
    )
  }

  getAllImages() {
    let imageList = []
    if (this.props.project.project) {
      const { project, waiting } = this.props.project

      for (let [i, img] of project.images.entries()) {
        if (!img.isDeleted) {
          let options = ['-', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
          this.props.positions[i] = img.gridPosition

          let imgSrc = `/public/${project._id}/${img.originalName}`
          imageList.push(
            <tr
              key={img._id}
              style={waiting ? { opacity: '.5' } : { opacity: '1' }}
            >
              <td>
                <img src={imgSrc} alt="" style={{ width: '60px' }} />
              </td>

                <SelectFieldGroup
                  name={`placeInGrid_${i}`}
                  onChange={this.updatePosition.bind(
                    this,
                    project._id,
                    project.name,
                    img._id,
                    img.originalName,
                    i
                  )}
                  options={options}
                  value={this.props.positions[i]}
                />
              </td>

            </tr>
          )
        }
      }
    }
    return imageList
  }

  render() {
    return (
      <div className={styles['image-list']}>
        <table className={styles['image-table']}>
          <tbody>{this.getAllImages()}</tbody>
        </table>
      </div>
    )
  }
}

const mapStateToProps = state => ({
  auth: state.auth,
  project: state.project
})

export default connect(
  mapStateToProps,
  { deleteImage, setGridPosition }
)(ImageList)

我从父组件收到道具 - 项目和位置(作为空数组)。

我希望这个问题在某种程度上是清楚的。我真的很感激任何帮助或指出我出错的地方。

编辑: 根据要求,为澄清起见,以下是代码的其他一些部分:

SelectFieldGroup.js

import React from 'react'
import PropTypes from 'prop-types'

import cx from 'classnames'
import globalStyles from './Bootstrap.module.css'
import commonStyles from './Common.module.sass'

const SelectFieldGroup = ({ name, onChange, options, value, disabled }) => {
  let optionArray = []
  for (let [index, option] of options.entries()) {
    optionArray.push(<option key={index}>{option}</option>)
  }

  return (
    <div className={globalStyles['form-group']}>
      <select
        value={value}
        className={cx(
          globalStyles['custom-select'],
          commonStyles['custom-select'],
          commonStyles['dark-input']
        )}
        name={name}
        onChange={onChange}
        disabled={disabled}
      >
        {optionArray}
      </select>
    </div>
  )
}

SelectFieldGroup.propTypes = {
  name: PropTypes.string.isRequired,
  onChange: PropTypes.func.isRequired,
  disabled: PropTypes.string
}

export default SelectFieldGroup

的相关部分imageActions.

export const setGridPosition = (
  projectId,
  projectName,
  imageId,
  imageName,
  position
) => dispatch => {
  dispatch(setWaiting())
  const data = {
    projectId: projectId,
    projectName: projectName,
    imageId: imageId,
    imageName: imageName,
    position: position
  }
  console.log(projectId)
  axios
    .post('/api/projects/set_grid_position', data)
    .then(res => {
      console.log(res.data)
      dispatch({
        type: SET_GRID_POSITION,
        payload: res.data
      })
    })
    .catch(err =>
      dispatch({
        type: GET_ERRORS,
        payload: {}
      })
    )
}

节点快递api:

router.post(
  '/set_grid_position',
  passport.authenticate('jwt', { session: false }),
  (req, res) => {
    const errors = {}
    Project.findById(req.body.projectId).then(currentProject => {
      let updatedProject = currentProject
      ProjectGridPosition.findOne({ position: req.body.position }).then(
        gridPosition => {
          if (req.body.position != '-') {
            // Mark the previous position of the image as empty.
            ProjectGridPosition.findOne({ imageId: req.body.imageId })
              .then(oldPos => {
                oldPos.isTaken = false
                oldPos.save()
              })
              .catch(err => res.status(400).json(err))
            // Set the gridPosition inside the image.
            currentProject.images.forEach(img => {
              if (img._id == req.body.imageId) {
                img.gridPosition = req.body.position
              }
            })
            currentProject.save(err => {
              if (err) res.json(err)
              else {
                updatedProject = currentProject
              }
            })

            if (gridPosition) {
              if (gridPosition.projectId) {
                Project.findById(gridPosition.projectId)
                  .then(project => {
                    console.log(project.name)
                    project.images.forEach(img => {
                      if (img.gridPosition == req.body.position) {
                        console.log(img.originalName)
                        img.gridPosition = '-'
                      }
                    })
                    project.save(err => {
                      if (err) {
                        res.json(err)
                      } else {
                        if (project == currentProject) {
                          updatedProject = currentProject
                        }
                      }
                    })
                  })
                  .catch(err => res.json(err))
              }
              gridPosition.projectId = req.body.projectId
              gridPosition.projectName = req.body.projectName
              gridPosition.imageId = req.body.imageId
              gridPosition.imageName = req.body.imageName
              gridPosition.isTaken = true
              gridPosition.save()

              res.json(updatedProject)
            } else {
              const newPosFields = {
                projectId: req.body.projectId,
                projectName: req.body.projectName,
                imageId: req.body.imageId,
                imageName: req.body.imageName,
                position: req.body.position,
                isTaken: true
              }
              new ProjectGridPosition(newPosFields)
                .save()
                .then(() => {
                  currentProject.save().then(() => {
                    res.json(currentProject)
                  })
                })

                .catch(err => res.json(err))
            }
          } else {
            currentProject.images.forEach(img => {
              if (img._id == req.body.imageId) {
                img.gridPosition = req.body.position
              }
            })
            currentProject.save(err => {
              if (err) res.json(err)
              ProjectGridPosition.findOne({ imageId: req.body.imageId }).then(
                newPos => {
                  newPos.isTaken = false
                  newPos.save().then(() => {
                    currentProject.save().then(() => {
                      res.json(currentProject)
                    })
                  })
                }
              )
            })
          }
        }
      )
    })
  }
)

最后,相关部分projectReducer.js

import {
  // ...
  SET_GRID_POSITION
} from '../actions/types'

const initialState = {
  project: null,
  projects: null,
  loading: false,
  waiting: false
}

export default function(state = initialState, action) {
  switch (action.type) {

    // ....

    case SET_GRID_POSITION:
      return {
        ...state,
        project: action.payload,
        waiting: false
      }
    default:
      return state
  }
}

标签: reactjsreact-redux

解决方案


所以我设法通过重组和完全摆脱 ProjectGridPosition 模型来使其工作。这样做会使整个过程变得简单得多。然后我完全重写了路线:

router.post(
  '/set_grid_position',
  passport.authenticate('jwt', { session: false }),
  async (req, res) => {
    let project = await getProjectById(req.body.projectId)
    const query = {
      'images.gridPosition': req.body.position
    }
    let formerRankProject = await getProjectByQuery(query)

    project = await updateRank(project, req.body.imageId, req.body.position)

    if (formerRankProject !== null) {
      formerRankProject = await UpdateIfDifferentProject(
        formerRankProject,
        project._id,
        req.body
      )
      formerRankProject.save()
    }

    project
      .save()
      .then(project => res.json(project))
      .catch(err => res.json(err))
  }
)

现在它正在工作。我不完全知道问题出在哪里,但正如@Tex 在评论中指出的那样,我有很多嵌套级别 - 所以可能肯定会出错。

我会将其标记为正确答案——尽管它更像是一种解决方法——所以人们知道,我还没有寻求帮助。


推荐阅读