React/Redux - 组件状态未更新
React/Redux - Component State not updating
看来我在 React/Redux 中遇到了一个非常普遍的问题。有很多人都有这个确切的问题,但原因可能相差很大,所以我无法确定可能的解决方案。
我正在尝试构建一个网页,其中包含一个可以通过按向上和向下按钮重新排序的列表。
我已经设法追踪更新状态(数组)直到减速器,但组件没有更新。我相信我没有正确更新组件的状态。
这是我的组件:
import React, { Component } from 'react';
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import { changeOrder } from "../actions/index.js";
// let list = ["apple", "banana", "orange", "mango", "passion fruit"];
export class Home extends Component {
constructor(props){
super(props);
this.renderList = this.renderList.bind(this);
}
goUp(position){
this.props.changeOrder(position, "up");
}
goDown(position){
this.props.changeOrder(position, "down");
}
renderList(fruit){
const position = this.props.list.indexOf(fruit);
return (
<div key={fruit}>
<li>{fruit}</li>
<button onClick={() => this.goUp(position)}>Up</button>
<button onClick={() => this.goDown(position)}>Down</button>
</div>
);
}
render() {
return (
<div>
<h1>This is the home component</h1>
<ol>
{this.props.list.map(this.renderList)}
</ol>
</div>
);
}
}
function mapStateToProps(state){
console.log(state);
return { list: state.list };
}
function mapDispachToProps(dispatch) {
return bindActionCreators({ changeOrder }, dispatch);
}
export default connect(mapStateToProps, mapDispachToProps)(Home);
操作:
export const GO_UP = "GO_UP";
export const GO_DOWN = "GO_DOWN";
export function changeOrder(position, direction) {
console.log("position: " + position + " | direction: " + direction);
switch (direction) {
case "up": {
return {
type: GO_UP,
payload: position
};
}
case "down": {
return {
type: GO_DOWN,
payload: position
};
}
}
}
减速器:
import { GO_UP, GO_DOWN } from "../actions/index.js";
let list = ["apple", "banana", "orange", "mango", "passion fruit"];
function arrayMove(arr, old_index, new_index) {
if (new_index >= arr.length) {
var k = new_index - arr.length + 1;
while (k--) {
arr.push(undefined);
}
}
arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
return arr; // for testing
}
export default function (state = list, action){
// debugger;
switch (action.type){
case GO_UP: {
let newState = arrayMove(state, action.payload, action.payload -1);
console.log(newState);
return newState;
}
case GO_DOWN: {
let newState = arrayMove(state, action.payload, action.payload +1);
console.log(newState);
return newState;
}
default: return list;
}
}
这里是reducer的Index.js:
import { combineReducers } from 'redux';
import ReducerList from "./reducer_list";
const rootReducer = combineReducers({
list: ReducerList
});
console.log(rootReducer);
export default rootReducer;
最后 index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import ReduxPromise from "redux-promise";
import App from './components/app';
import reducers from './reducers';
const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<App />
</Provider>
, document.querySelector('.container'));
如有任何帮助,我们将不胜感激!
问题出在你的reducer函数arrayMove()
中。您正在更改名为 arr
的现有数组。在它改变之后,React 组件并不知道 属性 state.list
实际上改变了,因为内存引用是跟随同一个旧数组(内容改变了)。
要告诉您的应用程序,该列表实际上已更改,您需要 return 新数组。就像你在 arrayMove
中的所有逻辑一样,最后你需要 return 类似的东西:
return [].concat(arr);
在函数式编程术语中,您的 arrayMove
是一个带有副作用的脏函数,因为它通过引用改变现有的 object/array。 "clean" 函数应该 return 对象的新实例。
当你使用 react-redux 时,你要确保你不改变状态,而你需要创建一个新的状态对象(浅拷贝)。有关详细信息,请参阅 。如果你改变以前的状态,Redux 将不知道状态是否已经更新。
在 arrayMove 中,您正在改变当前状态。而不是
arrayMove(state, action.payload, action.payload -1);
使用以下内容,
arrayMove(state.slice(), action.payload, action.payload -1);
看来我在 React/Redux 中遇到了一个非常普遍的问题。有很多人都有这个确切的问题,但原因可能相差很大,所以我无法确定可能的解决方案。 我正在尝试构建一个网页,其中包含一个可以通过按向上和向下按钮重新排序的列表。
我已经设法追踪更新状态(数组)直到减速器,但组件没有更新。我相信我没有正确更新组件的状态。
这是我的组件:
import React, { Component } from 'react';
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import { changeOrder } from "../actions/index.js";
// let list = ["apple", "banana", "orange", "mango", "passion fruit"];
export class Home extends Component {
constructor(props){
super(props);
this.renderList = this.renderList.bind(this);
}
goUp(position){
this.props.changeOrder(position, "up");
}
goDown(position){
this.props.changeOrder(position, "down");
}
renderList(fruit){
const position = this.props.list.indexOf(fruit);
return (
<div key={fruit}>
<li>{fruit}</li>
<button onClick={() => this.goUp(position)}>Up</button>
<button onClick={() => this.goDown(position)}>Down</button>
</div>
);
}
render() {
return (
<div>
<h1>This is the home component</h1>
<ol>
{this.props.list.map(this.renderList)}
</ol>
</div>
);
}
}
function mapStateToProps(state){
console.log(state);
return { list: state.list };
}
function mapDispachToProps(dispatch) {
return bindActionCreators({ changeOrder }, dispatch);
}
export default connect(mapStateToProps, mapDispachToProps)(Home);
操作:
export const GO_UP = "GO_UP";
export const GO_DOWN = "GO_DOWN";
export function changeOrder(position, direction) {
console.log("position: " + position + " | direction: " + direction);
switch (direction) {
case "up": {
return {
type: GO_UP,
payload: position
};
}
case "down": {
return {
type: GO_DOWN,
payload: position
};
}
}
}
减速器:
import { GO_UP, GO_DOWN } from "../actions/index.js";
let list = ["apple", "banana", "orange", "mango", "passion fruit"];
function arrayMove(arr, old_index, new_index) {
if (new_index >= arr.length) {
var k = new_index - arr.length + 1;
while (k--) {
arr.push(undefined);
}
}
arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
return arr; // for testing
}
export default function (state = list, action){
// debugger;
switch (action.type){
case GO_UP: {
let newState = arrayMove(state, action.payload, action.payload -1);
console.log(newState);
return newState;
}
case GO_DOWN: {
let newState = arrayMove(state, action.payload, action.payload +1);
console.log(newState);
return newState;
}
default: return list;
}
}
这里是reducer的Index.js:
import { combineReducers } from 'redux';
import ReducerList from "./reducer_list";
const rootReducer = combineReducers({
list: ReducerList
});
console.log(rootReducer);
export default rootReducer;
最后 index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import ReduxPromise from "redux-promise";
import App from './components/app';
import reducers from './reducers';
const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<App />
</Provider>
, document.querySelector('.container'));
如有任何帮助,我们将不胜感激!
问题出在你的reducer函数arrayMove()
中。您正在更改名为 arr
的现有数组。在它改变之后,React 组件并不知道 属性 state.list
实际上改变了,因为内存引用是跟随同一个旧数组(内容改变了)。
要告诉您的应用程序,该列表实际上已更改,您需要 return 新数组。就像你在 arrayMove
中的所有逻辑一样,最后你需要 return 类似的东西:
return [].concat(arr);
在函数式编程术语中,您的 arrayMove
是一个带有副作用的脏函数,因为它通过引用改变现有的 object/array。 "clean" 函数应该 return 对象的新实例。
当你使用 react-redux 时,你要确保你不改变状态,而你需要创建一个新的状态对象(浅拷贝)。有关详细信息,请参阅
在 arrayMove 中,您正在改变当前状态。而不是
arrayMove(state, action.payload, action.payload -1);
使用以下内容,
arrayMove(state.slice(), action.payload, action.payload -1);