当输入字段已使用 useState() 映射时,如何使用 useSelector() 连接 redux 存储

IT技术 reactjs redux react-redux react-hooks
2021-05-12 17:47:23

我在玩新的 React-Redux Hooks 库

我有一个react组件,它有两个输入字段,它们使用 useState() - desc 和数量更新到react存储。为了在编辑字段时更新对 redux 存储的更改,我使用 onBlur 事件并调用调度到 redux 存储。这很好用。

当我想从另一个组件中清除字段时,我希望它以与基于类的函数相同的方式通过 connect & map State to Props 工作,但是对于这个具有功能组件的我需要利用 useSelector()。我不能这样做,因为标识符 desc 和数量已经被 useState() 使用

我在这里错过了什么?

import { useDispatch, useSelector } from "react-redux"
import { defineItem, clearItem } from "../store/actions"

const ItemDef = props => {
  const dispatch = useDispatch()

  const [desc, setDesc] = useState(itemDef.desc)
  const [amount, setAmount] = useState(itemDef.amount)

  //MAPSTATETOPROPS
  //I WANT TO HAVE THESE VALUES UPDATED WHEN REDUX STORE CHANGES FROM ANOTHER COMPONENT
  //THESE LINES WILL CAUSE ERROR to effect - identifier has already been declared
  const desc = useSelector(state => state.pendingItem.desc)
  const amount = useSelector(state => state.pendingItem.amount)

  return (
    <div>
      <p>Define new items to be added below - before clicking Add Item</p>
      <input
        value={desc}
        type="text"
        name="desc"
        placeholder="Description of Item"
        onChange={e => setDesc(e.target.value)}
        //Use onBlur Event so that changes are only submitted to store when field loses focus
        onBlur={e => dispatch(defineItem(desc, amount))}
      />
      &nbsp;
      <input
        value={amount}
        type="number"
        name="amount"
        placeholder="Amount"
        onChange={e => setAmount(e.target.value)}
        //Use onBlur Event so that changes are only submitted to store when field loses focus
        onBlur={e => {
          dispatch(defineItem(desc, amount))
        }}
      />
    </div>
  )
}

export default ItemDef
1个回答

解决方案 - 存储库中有完整代码

我通过使用 useSelector(将 redux state 的 pendingItem 部分映射到 itemDef)和 setEffect 钩子将 useState 应用到 state item(来自输入)或 itemDef(来自 Redux State - 当 redux 被另一个组件更新时会发生这种情况)制定了一个解决方案或通过添加项目到输入按钮)

我已经在下面发布了工作组件。我还发布了这个小应用程序来演示如何使用带有基于类的组件和使用钩子的功能组件的 reacdt-redux 库

存储库是https://github.com/Intelliflex/hiresystem

//**************************************************************************************************
//***** ITEMDEF COMPONENT - Allow entry of new Items (dispatched from button in HireList Table) ****
//**************************************************************************************************
import React, { useState, useEffect, useRef } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { defineItem, clearItem } from '../store/actions'
import _ from 'lodash'

const ItemDef = props => {
  //BRING IN DISPATCH FROM REDUX STORE
  const dispatch = useDispatch()

  //DEFINE SELECTOR - EQUIV TO MAPSTATETOPROPS
  const { itemDef } = useSelector(state => ({
    itemDef: state.pendingItem
  }))

  const [item, setItem] = useState({ desc: '', amount: 0 })

  const onChange = e => {
    setItem({
      ...item,
      [e.target.name]: e.target.value
    })
  }

  const prevItem = useRef(item)
  useEffect(() => {
    //WE NEED TO CONDITIONALLY UPDATE BASED ON EITHER STORE BEING CHANGED DIRECTLY OR INPUT FORM CHANGING
    if (!_.isEqual(item, prevItem.current)) {
      //INPUT HAS CHANGED
      setItem(item)
    } else if (!_.isEqual(item, itemDef)) {
      //REDUX STATE HAS CHANGED
      setItem(itemDef)
    }
    prevItem.current = item
  }, [item, itemDef]) //Note: item and ItemDef are passed in as second argument in order to use setItem

  const clearIt = e => {
    dispatch(clearItem())
  }

  const addIt = e => {
    dispatch(defineItem({ desc: 'MY NEW ITEM', amount: 222 }))
  }

  return (
    <div>
      <p>Define new items to be added below - before clicking Add Item</p>
      <input
        value={item.desc}
        type='text'
        name='desc'
        placeholder='Description of Item'
        onChange={onChange}
        //Use onBlur Event so that changes are only submitted to store when field loses focus
        onBlur={e => dispatch(defineItem(item))}
      />
      &nbsp;
      <input
        value={item.amount}
        type='number'
        name='amount'
        placeholder='Amount'
        onChange={onChange}
        //Use onBlur Event so that changes are only submitted to store when field loses focus
        onBlur={e => dispatch(defineItem(item))}
      />
      &nbsp;
      <button onClick={clearIt}>CLEAR ITEM</button>
      &nbsp;
      <button onClick={addIt}>ADD ITEM TO INPUT</button>
    </div>
  )
}

export default ItemDef