使用 useSelector 的形式值中的异相数据

out of phase data in form value using useSelector

晚上好

我正在做一个练习,只是一个使用 redux-thunk 获取数据的简单 CRUD。 我想修改一个 selected 项目并显示字段数据,然后操作这些值。 为此,我有一个名为 useForm 的自定义挂钩:

import { useState } from "react"

export const useForm = (initialState = {}) => {

    const [values, setValues] = useState(initialState)

    const reset = () => {
        setValues(initialState)
    }

    const handleInputChange = ({ target }) => {

        setValues({
            ...values,
            [target.name]: target.value
        })


    }

    return [values, handleInputChange, reset]

这是我的 UpdateItem 组件(我知道重构是必须的):

import axios from 'axios'
import React from 'react'

import { useForm } from '../hooks/useForm'
import { baseURL } from '../configuration/baseURL'

import { useDispatch, useSelector } from 'react-redux';
import { types } from '../types/types';
import { useHistory } from 'react-router-dom'

import Swal from 'sweetalert2'


export default function UpdateItem() {

    const history = useHistory()

    const dispatch = useDispatch()
    const { selected } = useSelector(state => state.axiosDataReducer)
    const { data } = useSelector(state => state.axiosDataReducer)

    const id = selected?.id

    const selectedItemtoModify = data?.filter(x => x?.id === id)
    console.log(data !== undefined && selectedItemtoModify)

    console.log(selectedItemtoModify[0]?.name)
    console.log(selectedItemtoModify[0]?.cost)
    console.log(selectedItemtoModify[0]?.department[0].name)
    console.log(selectedItemtoModify[0]?.department[0].identification)
    console.log(selectedItemtoModify[0]?.category[0].name)
    console.log(selectedItemtoModify[0]?.category[0].id)

    const name = selectedItemtoModify[0]?.name
    const cost = selectedItemtoModify[0]?.cost
    const departmentName = selectedItemtoModify[0]?.department[0].name
    const departmentIdentification = selectedItemtoModify[0]?.department[0].identification
    const categoryName = selectedItemtoModify[0]?.category[0].name
    const categoryId = selectedItemtoModify[0]?.category[0].id


    const [formValues, handleInputChange] = useForm({

        newName: name,
        newCost: cost,
        newDepartmentName: departmentName,
        newDepartmentIdentification: departmentIdentification,
        newCategoryName: categoryName,
        newCategoryId: categoryId
    })

    const {
        newName,
        newCost,
        newDepartmentName,
        newDepartmentIdentification,
        newCategoryName,
        newCategoryId } = formValues

    const handleUpdateItem = async (e) => {
        e.preventDefault()
        try {
            await axios.put(`${baseURL}${id}`, {
                "id": +id,
                "name": newName,
                "cost": +newCost,
                "department": [
                    {
                        "name": newDepartmentName,
                        "identification": newDepartmentIdentification
                    }
                ],
                "category": [
                    {
                        "name": newCategoryName,
                        "id": +newCategoryId
                    }
                ]
            })
            const modified = await axios.get(`${baseURL}${id}`)
            const { data } = modified

            dispatch({
                type: types.modify,
                modifiedItem: data
            });
            Swal.fire({
                icon: 'success',
                title: 'Your item has been modified',
                showConfirmButton: false,
                timer: 1500
            })
            setTimeout(() => {
                history.push('/')
            }, 1500);

        } catch (error) {
            Swal.fire({
                icon: 'error',
                title: 'Oops...',
                text: 'Something went wrong!',
                footer: 'Unable to modify item, who passes the id?'
            })
            return dispatch({
                type: types.error,
                msg: 'Unable to modify item'
            })
        }
    }

    return (
        <div className='container mb-5 pb-3 bg-light'>
            <form className='mt-3' onSubmit={handleUpdateItem}>

                <input
                    className='input mb-1 p-3'
                    type='text'
                    title='Name'
                    placeholder='Name'
                    name='newName'
                    autoComplete='off'
                    value={newName}
                    onChange={handleInputChange} />
                <input
                    className='input mb-1 p-3'
                    type='text'
                    title='Cost'
                    placeholder='Cost'
                    name='newCost'
                    autoComplete='off'
                    value={newCost}
                    onChange={handleInputChange} />
                <input
                    className='input mb-1 p-3'
                    type='text'
                    title='Department Name'
                    placeholder='Department Name'
                    name='newDepartmentName'
                    autoComplete='off'
                    value={newDepartmentName}
                    onChange={handleInputChange} />
                <input
                    className='input mb-1 p-3'
                    type='text'
                    title='Department Identification'
                    placeholder='Department Identification'
                    name='newDepartmentIdentification'
                    autoComplete='off'
                    value={newDepartmentIdentification}
                    onChange={handleInputChange} />
                <input
                    className='input mb-1 p-3'
                    type='text'
                    title='Category Name'
                    placeholder='Category Name'
                    name='newCategoryName'
                    autoComplete='off'
                    value={newCategoryName}
                    onChange={handleInputChange} />
                <input
                    className='input mb-1 p-3'
                    type='text'
                    title='Category Id'
                    placeholder='Category Id'
                    name='newCategoryId'
                    autoComplete='off'
                    value={newCategoryId}
                    onChange={handleInputChange} />

                <button className='btn btn-success ' type=' submit'>
                    Modify Item
                </button>
            </form>
        </div>
    )
}

这是减速器:

import { types } from "../types/types";

const initialState = {
    data: null,
    selected: null,
    deleted: '',
    created: null,
    modified: null,
    error: ''
}

export const axiosDataReducer = (state = initialState, action) => {
    switch (action.type) {
        case types.get:
            return {
                ...state,
                data: action.data
            }
        case types.selected:
            return {
                ...state,
                selected: action.selectedItem
            }
        case types.delete:
            return {
                ...state,
                data: state.data.filter(item => item.id !== action.deletedItem.id),
                deleted: action.deletedItem
            }
        case types.created:
            return {
                ...state,
                created: action.createdItem
            }
        case types.modified:
            return {
                ...state,
                modified: action.modifiedItem
            }

        case types.error:
            return {
                ...state,
                error: action.msg
            }
        default:
            return state;
    }
}

一切正常,但是,当我 select 来自 table 的选项时:

table fragment

它没有像预期的那样工作,因为获取数据有延迟并且表单一开始没有值,但是在获取值之后但没有显示在表单中: first nothing then updates

我可以引入一些其他值,并提交这些值并完美运行

然后当我 select 一些其他字段时,它显示以前的值而不是实际的 select 我编辑的值: I've selected Raspberries and I obtain Cherries as console.log show...and it keeps going

这个异相数据获取呢? @Shyam https://whosebug.com/users/8884388/shyam?

已编辑 我在 UpdateItem.js 组件中进行了此更改,结果仍然相同: 如何等待 selected 完全加载?

    const { selected } = useSelector(state => state.axiosDataReducer)

    console.log(selected)

    console.log(selected?.name)
    console.log(selected?.cost)
    console.log(selected?.department[0].name)
    console.log(selected?.department[0].identification)
    console.log(selected?.category[0].name)
    console.log(selected?.category[0].id)

    const id = selected?.id
    const name = selected?.name
    const cost = selected?.cost
    const departmentName = selected?.department[0].name
    const departmentIdentification = selected?.department[0].identification
    const categoryName = selected?.category[0].name
    const categoryId = selected?.category[0].id

使用我的解决方案进行编辑 我做了什么:

我将组件一分为二: UpdateItem.js

import axios from 'axios'
import React from 'react'

import { useForm } from '../hooks/useForm'
import { baseURL } from '../configuration/baseURL'

import { useDispatch } from 'react-redux';
import { types } from '../types/types';
import { useHistory } from 'react-router-dom'

import Swal from 'sweetalert2'


export default function UpdateItem({ id, name, cost, departmentName, departmentIdentification, categoryName, categoryId }) {

    const history = useHistory()

    const dispatch = useDispatch()

    const [formValues, handleInputChange] = useForm({

        newName: name,
        newCost: cost,
        newDepartmentName: departmentName,
        newDepartmentIdentification: departmentIdentification,
        newCategoryName: categoryName,
        newCategoryId: categoryId
    })

    const {
        newName,
        newCost,
        newDepartmentName,
        newDepartmentIdentification,
        newCategoryName,
        newCategoryId } = formValues

    const handleUpdateItem = async (e) => {
        e.preventDefault()
        try {
            await axios.put(`${baseURL}${id}`, {
                "id": +id,
                "name": newName,
                "cost": +newCost,
                "department": [
                    {
                        "name": newDepartmentName,
                        "identification": newDepartmentIdentification
                    }
                ],
                "category": [
                    {
                        "name": newCategoryName,
                        "id": +newCategoryId
                    }
                ]
            })
            const modified = await axios.get(`${baseURL}${id}`)
            const { selected } = modified

            dispatch({
                type: types.modify,
                modifiedItem: selected
            });
            Swal.fire({
                icon: 'success',
                title: 'Your item has been modified',
                showConfirmButton: false,
                timer: 1500
            })
            setTimeout(() => {
                history.push('/')
            }, 1500);

        } catch (error) {
            Swal.fire({
                icon: 'error',
                title: 'Oops...',
                text: 'Something went wrong!',
                footer: 'Unable to modify item, who passes the id?'
            })
            return dispatch({
                type: types.error,
                msg: 'Unable to modify item'
            })
        }
    }

    return (
        <div className='container mt-5 mb-5 pb-3 bg-light'>
            <form className='mt-3' onSubmit={handleUpdateItem}>

                <input
                    className='input mb-1 p-3'
                    type='text'
                    title='Name'
                    placeholder='Name'
                    name='newName'
                    autoComplete='off'
                    value={newName}
                    onChange={handleInputChange} />
                <input
                    className='input mb-1 p-3'
                    type='text'
                    title='Cost'
                    placeholder='Cost'
                    name='newCost'
                    autoComplete='off'
                    value={newCost}
                    onChange={handleInputChange} />
                <input
                    className='input mb-1 p-3'
                    type='text'
                    title='Department Name'
                    placeholder='Department Name'
                    name='newDepartmentName'
                    autoComplete='off'
                    value={newDepartmentName}
                    onChange={handleInputChange} />
                <input
                    className='input mb-1 p-3'
                    type='text'
                    title='Department Identification'
                    placeholder='Department Identification'
                    name='newDepartmentIdentification'
                    autoComplete='off'
                    value={newDepartmentIdentification}
                    onChange={handleInputChange} />
                <input
                    className='input mb-1 p-3'
                    type='text'
                    title='Category Name'
                    placeholder='Category Name'
                    name='newCategoryName'
                    autoComplete='off'
                    value={newCategoryName}
                    onChange={handleInputChange} />
                <input
                    className='input mb-1 p-3'
                    type='text'
                    title='Category Id'
                    placeholder='Category Id'
                    name='newCategoryId'
                    autoComplete='off'
                    value={newCategoryId}
                    onChange={handleInputChange} />

                <button className='btn btn-success ' type=' submit'>
                    Modify Item
                </button>
            </form>
        </div>
    )
}

和另一个: ConditionalRenderUpdateItem

import React from 'react'

import { useSelector } from 'react-redux';
import UpdateItem from '../screen/UpdateItem';


export default function ConditionalRenderUpdateItem() {

    const { selected } = useSelector(state => state.axiosDataReducer)

    console.log(selected)

    console.log(selected?.name)
    console.log(selected?.cost)
    console.log(selected?.department[0].name)
    console.log(selected?.department[0].identification)
    console.log(selected?.category[0].name)
    console.log(selected?.category[0].id)

    const id = selected?.id
    const name = selected?.name
    const cost = selected?.cost
    const departmentName = selected?.department[0].name
    const departmentIdentification = selected?.department[0].identification
    const categoryName = selected?.category[0].name
    const categoryId = selected?.category[0].id
    return (
        <div>
            {(selected !== null) &&
                <UpdateItem
                    id={id}
                    name={name}
                    cost={cost}
                    departmentName={departmentName}
                    departmentIdentification={departmentIdentification}
                    categoryName={categoryName}
                    categoryId={categoryId}
                />}
        </div>
    )
}

就是这样

由于新问题再次编辑

正如我在下面的评论中所解释的,现在我遇到了同样的问题,用以前的数据填充表单值...按照@Drew Reese 的建议修复此问题 在从我的自定义挂钩中提取重置功能后,我以这种方式实现了 useEffect:

const [formValues, handleInputChange, reset] = useForm({

        newName: name,
        newCost: cost,
        newDepartmentName: departmentName,
        newDepartmentIdentification: departmentIdentification,
        newCategoryName: categoryName,
        newCategoryId: categoryId
    })

    useEffect(() => {
        reset()
    }, [id])

在UpdateItem.js

这是我正在使用的自定义挂钩,由 Udemy 的 tehacher Fernando Herrera 创建:

使用表格

import { useState } from "react"

export const useForm = (initialState = {}) => {

    const [values, setValues] = useState(initialState)

    const reset = () => {
        setValues(initialState)
    }

    const handleInputChange = ({ target }) => {

        setValues({
            ...values,
            [target.name]: target.value
        })


    }

    return [values, handleInputChange, reset]
}

编辑为最终答案

它还需要包含所有表单值作为 useEffect 的依赖项:

useEffect(() => {
        reset()
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [id, name, cost, departmentName, departmentIdentification, categoryName, categoryId])

您的问题和评论有点不清楚,但听起来您需要在选择新值并且 state.axiosDataReducer 状态已更新时重置表单数据。

当它在您的 redux 存储中更新时,该组件将重新呈现,您将拥有最新的选定值。无需等待,React 和 redux 将为组件提供更新后的值。

记忆表单的初始数据值并传递给挂钩,并使用依赖于 selected 状态的 useEffect 挂钩调用 useForm 挂钩的 reset 功能。当 selected 状态更新时,useEffect 挂钩将触发其回调,并且应调用 reset 函数并使用最新的 initialData 值重置表单字段。

export default function UpdateItem() {
  ...
  const { data, selected } = useSelector(state => state.axiosDataReducer);

  const { id } = selected;

  const initialData = React.useMemo(() => {
    const selectedItemtoModify = data?.filter(x => x?.id === id);

    return {
      newName: selectedItemtoModify[0]?.name,
      newCost: selectedItemtoModify[0]?.cost,
      newDepartmentName: selectedItemtoModify[0]?.department[0].name,
      newDepartmentIdentification: selectedItemtoModify[0]?.department[0].identification,
      newCategoryName: selectedItemtoModify[0]?.category[0].name,
      newCategoryId: selectedItemtoModify[0]?.category[0].id
    };
  }, [selected]);

  const [formValues, handleInputChange, reset] = useForm(initialData);

  useEffect(() => {
    reset();
  }, [selected]);

  const {
    newName,
    newCost,
    newDepartmentName,
    newDepartmentIdentification,
    newCategoryName,
    newCategoryId,
  } = formValues;