从 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"/>
我刚刚为我的排序算法可视化工具实现了缩减器,并试图将我的数组状态设置为排序算法的结果。我 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"/>