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

Posted

技术标签:

【中文标题】当输入字段已经使用 useState() 映射时,如何使用 useSelector() 连接 redux 存储【英文标题】:How to connect redux store using useSelector() when input fields already mapped using useState() 【发布时间】:2019-05-21 05:52:35 【问题描述】:

我正在玩新的 React-Redux Hooks 库

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

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

我在这里错过了什么?

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 状态的 pendingItem 部分映射到 itemDef)和 setEffect 钩子将 useState 应用于状态项(来自输入)或 itemDef(来自 Redux 状态 - 这发生在 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

【讨论】:

在这种情况下 lodash 是做什么用的?我一点也不熟悉 @mph85 他正在使用它来比较对象:_.isEqual(item, prevItem.current .. lodash 是一个具有实用功能的库。只需阅读 1 分钟的文档,您就会明白它 = )

以上是关于当输入字段已经使用 useState() 映射时,如何使用 useSelector() 连接 redux 存储的主要内容,如果未能解决你的问题,请参考以下文章

如何使用映射 React 从 useState 添加 2 个键?

反应钩子 useState 不使用 onSubmit 更新

单击发送消息后如何重置输入字段

使用 ref 从父函数组件传递时 useState 不更新数据

在 useState 的调度中使用未声明的字段时如何获取打字稿错误

当输入字段变得可见时,Vue会关注输入字段