从 react reducer 设置状态 returns 正确的值但不会导致重新渲染

Setting state from react reducer returns proper value but doesn't cause re-render

我刚刚为我的排序算法可视化工具实现了缩减器,并试图将我的数组状态设置为排序算法的结果。我 99% 确定我的 reducer 正在接收排序后的数组然后返回它(因为我做了一些 console.logs),而且我也很确定变量本身确实发生了变化。

这是我的 reducer 和数组变量(*请注意,函数中的值将是数组):

export const ACTIONS = {
    SET_VALUES: 'set-values'
}

function reducer(state, action) {
  switch (action.type) {
    case ACTIONS.SET_VALUES:
      console.log(action.payload.values)
      return action.payload.values
    default:
      return state
  }
}


const [values, dispatch] = useReducer(reducer, [])

这里是调用 dispatch 的排序算法:

  export function bubbleSort(array, dispatch) {
    var testArray = array
    console.log('sorting')
    var sorted = false
    while (!sorted) {
        var changed = false;
        for (var i = 0; i < testArray.length-1; i++) {
            if (testArray[i] > testArray[i+1]) {
                changed = true;
                var smaller = testArray[i]
                testArray[i] = testArray[i+1]
                testArray[i+1] = smaller
            }
        }
        if (!changed) {
            sorted = true
        }
    }
    dispatch({ type: ACTIONS.SET_VALUES, payload: { values: testArray}})
    console.log('sorted')
    console.log(array)   
} 

打印传递给函数的原始数组(值)时,它是排序的。然而,屏幕上反映数组本身的条形图并没有改变,这让我相信没有发生重新渲染,并且条形图使用的是变量(值)的旧状态。有谁知道如何解决这个问题?

你几乎做对了一切。问题是 React 使用引用相等性 a===b 来检查是否发生了变化。因此,由于您对数组进行了适当的排序,引用没有改变,所以所有 useReducer 钩锯都是 state===state,所以它没有重新渲染。

我所做的更改是在冒泡排序的开始创建一个新数组,这样它就不会发生变化。

var testArray = array.slice();

const { useReducer } = React;
const ACTIONS = {
  SET_VALUES: "set-values",
};

function reducer(state, action) {
  switch (action.type) {
    case ACTIONS.SET_VALUES:
      console.log(action.payload.values);
      return action.payload.values;
    default:
      return state;
  }
}

function bubbleSort(array, dispatch) {
  var testArray = array.slice();
  console.log("sorting");
  var sorted = false;
  while (!sorted) {
    var changed = false;
    for (var i = 0; i < testArray.length - 1; i++) {
      if (testArray[i] > testArray[i + 1]) {
        changed = true;
        var smaller = testArray[i];
        testArray[i] = testArray[i + 1];
        testArray[i + 1] = smaller;
      }
    }
    if (!changed) {
      sorted = true;
    }
  }
  dispatch({ type: ACTIONS.SET_VALUES, payload: { values: testArray } });
  console.log("sorted");
  console.log(array);
}

const App = () => {
  const [values, dispatch] = useReducer(reducer, [5, 2, 3, 9, 10, 234, 432, 1]);

  return (
    <div>
      <button
        onClick={() => {
          bubbleSort(values, dispatch);
        }}
      >Sort</button>
      <div>{values.join(", ")}</div>
    </div>
  );
};

ReactDOM.render(<App/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>