首页 > 解决方案 > 在 react redux 中唯一地计算某些元素

问题描述

我有一个反应组件,它将加载第 3 方内容,因此需要一个索引。该索引基于位置属性,它是一个枚举,并且对于具有相同位置的每个组件都会递增。

例子:

位置 a = 索引 a-1

位置 b = 索引 b-1

位置 a = 索引 a-2

我不想将计数器存储在函数或其他东西中,因为应用程序应该是无状态的,以避免在服务器端呈现它时出现问题。因此,我尝试将计数器(需要不时重置)存储在 redux 中,但这会导致问题,因为动作的调度是异步的,我无法设法在两个渲染之间的某个位置增加索引成分。因此,即使在 redux 状态下的索引增加时,我也总是得到所有位置的索引 1。

const Mycomponent = (props) => {
    // this should avoid to update the position after the initialization
    const [positionCount] = useState(props.positionCount); 

    // this should update the counter but its fired too late so that the 2. component will get the same counter as the first one
    if (positionCount === props.positionCount) {
        props.increasePositionCounter(props.position);
    }

    ...
}

@Edit 该位置是从上面的组件中给出的,不应更改。但是根据已经渲染了多少具有相同位置的组件,我们需要一个不同的索引。

增量代码如下所示:

export function exampleReducer(state, action) {
    let newState;

    switch (action.type) {
        // ...
        case actions.INCREASE_COUNTER:
            newState = {
                ...state,
                counter: {
                    ...state.counter,
                    [action.payload.position]: state.counter[action.payload.position] + 1
                }
            };
            break;
        // ...
    }

    return newState;
}

当我渲染一个位置为 a 的组件时,它应该获得索引 a-1。现在我渲染另一个具有相同位置 a 的组件,它应该获得索引 a-2 等等。但是然后我用另一个位置渲染另一个组件,比如说b,它应该得到索引b-1。但是我不知道在哪里可以跟踪到目前为止每个位置渲染了多少组件。希望这有助于更好地理解。

@Edit2: 我已经与第 3 方内容的开发人员进行了交谈,他们告诉我另一种我根本不需要索引的方式。所以这个问题对于我的情况来说有点解决了。但是,如果有人知道如何解决该问题,请随时发布!

标签: javascriptreactjsreduxreact-redux

解决方案


您可以简单地跟踪所有渲染的子组件以及它们在您的状态中各自的位置和索引。

这样,您可以轻松地检索具有特定位置的元素的最大使用索引或删除某些项目:

//dependencies
const { render } = ReactDOM,
      { createStore } = Redux,
      { connect, Provider } = ReactRedux
      
//store initialization
const defaultState = {
        children:[]
      },
      appReducer = (state=defaultState, action) => {
        switch(action.type){
          case 'APPEND_CHILD': {
            const {children} = state,
                  {payload:pos} = action
            if(!pos.length) return state
            const maxIndex = Math.max(0,...children
                    .filter(({position}) => position == pos)
                    .map(({index}) => index)
                   )
            return {...state, children: [...state.children,{position:pos, index:maxIndex+1}]}
          }
          default: return state
        }     
      },
      store = createStore(appReducer) 
//append child component
const AppendChildForm = ({pos,onAppendChild}) => {
  return (
    <form onSubmit={e=>(e.preventDefault(),onAppendChild(pos),e.target.reset(),pos=null)}>
      <label>Child position<input maxLength="1" onKeyUp={event => pos=event.target.value}></input></label>
      <button>Append Child</button>
    </form>
   )
}
//append child container
var mapDispatchToProps = dispatch => ({onAppendChild: pos =>  dispatch({type:'APPEND_CHILD',payload:pos})})
const AppendChildContainer = connect(null,mapDispatchToProps)(AppendChildForm)
//child component
const ChildComponent = ({position,index}) => <div>My position is {position} and my index is {index}</div>
//parent component
const ParentComponent = ({children}) => (
  <div>
    {children.map(({index,position},key) => <ChildComponent index={index} position={position} key={key} />)}
  </div>
)
//parent container
var mapStateToProps = ({children}) => ({children:[...children]})
const ParentContainer = connect(mapStateToProps)(ParentComponent)
//provider
render(
  <Provider store={store}>
    <AppendChildContainer />
    <ParentContainer />
  </Provider>,
  document.getElementById('root')
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script><script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.4/redux.min.js"></script><script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.1.1/react-redux.min.js"></script><div id="root"></div>


推荐阅读