React-redux状态和道具更新但组件没有重新渲染

时间:2017-09-12 08:41:38

标签: javascript reactjs redux frontend

我发现了一个让我头疼的问题,我目前正在使用反应dan redux来处理CRUD UI。

一切正常,直到我发现我的“编辑页面”不能正常工作,我发现在将我的全局状态从reducer映射到本地组件道具后,显然组件根本没有更新或重新渲染。以下是我的javascript示例:

index.js:

import React from "react";
import ReactDOM from "react-dom";
import {Router, Route, IndexRoute, hashHistory} from "react-router";
import {Provider} from "react-redux";
import store from "./store/store";

import Department from "./components/pages/department/index";
import DepartmentAdd from "./components/pages/department/add";
import DepartmentEdit from "./components/pages/department/edit";

const app = document.getElementById("app");
ReactDOM.render(
    <Provider store={store}>
        <Router history={hashHistory}>

            <Route path="/" component={Layout} onEnter={requireLogin}>
                <IndexRoute component={Dashboard} onEnter={requireLogin}/>
                <Route path="error404" component={ERROR404}/>

                <Route path="department" onEnter={requireLogin}>
                    <IndexRoute component={Department}/>
                    <Route path="add" component={DepartmentAdd}/>
                    <Route path="edit/:id" component={DepartmentEdit}/>
                </Route>
            </Route>
        </Router>
    </Provider>
    , app);

departmentReducer.js

export default function (state = {
    message: null,
    activeRow: {},
    error: false

}, action) {

    switch (action.type) {

        case "GET_SINGLE_DEPARTMENT": {
            state = {
                ...state,
                activeRow: {...action.payload.data},
                message: action.payload.success.message,
                error: false
            };
            break;
        }

        case "GET_SINGLE_DEPARTMENT_FAILED": {
            state = {...state, message: action.payload.error.message, error: true};
            break;
        }
        default: {
            state = {...state};
            break;
        }

    }
    return state;
}

store.js

import {createStore, applyMiddleware} from "redux";
import thunk from "redux-thunk";
import {createLogger} from "redux-logger";
import promise from "redux-promise-middleware";
import {composeWithDevTools} from "redux-devtools-extension";
import persistState from 'redux-localstorage';

import combineReducer from "./../reducers/combineReducer";

const middleware = composeWithDevTools(applyMiddleware(promise(), thunk, createLogger()), persistState());

export default createStore(combineReducer, middleware);

combineReducer.js

import {combineReducers} from "redux";
import departmentReducer from "./departmentReducer";

export default combineReducers({
    departmentReducer
});

departmentActions.js

import axios from "axios";

export function getSingleDepartment(id = 0) {
    return function (dispatch) {
        axios.get('department/show/' + id).then((response) => {
            dispatch({type: "GET_SINGLE_DEPARTMENT", payload: response.data})
        }).catch((error) => {
            dispatch({type: "GET_SINGLE_DEPARTMENT_FAILED", payload: error.response.data})
        })
    }
}

最后是edit.js

import React from "react";
import ContentHeader from "./../shared/ContentHeader";
import {connect} from "react-redux";
import {hashHistory} from "react-router";
import {getSingleDepartment} from "./../../../actions/departmentActions";
import ErrorAlert from "./../shared/ErrorAlert";
import SuccessAlert from "./../shared/SuccessAlert";

@connect((store) => {
    return {
        activeRow: store.departmentReducer.activeRow,
        error: store.departmentReducer.error,
        message: store.departmentReducer.error,
    }
})

export default class index extends React.Component {

    constructor() {
        super();
        this.state
    }

    componentDidMount() {
        this.props.dispatch(getSingleDepartment(this.props.params.id));
    }

    render() {
        const {namaDepartment, deskripsiDepartment} = this.props.activeRow;
        return (
            <section>
                <ContentHeader title="Edit Department"/>
                <div class="body">
                    <div class="bodyWrapper col-lg-12 col-md-12 col-sm-12 col-xs-12">
                        <ErrorAlert error={this.props.error} message={this.props.message}/>
                        <SuccessAlert error={this.props.error} message={this.props.message}/>
                        <form onSubmit={this.saveProfile.bind(this)}>
                            <div className="half col-lg-6 col-md-6 col-sm-12 col-xs-12">
                                <div className="feWrapper">
                                    <label for="nama">Nama Department</label>
                                    <input defaultValue={namaDepartment}
                                           type="text"
                                           ref="nama"
                                           id="nama"
                                           name="nama"
                                           className="form-control"/>
                                </div>
                                <div className="feWrapper">
                                    <label for="nama">Deskripsi Department</label>
                                    <textarea defaultValue={deskripsiDepartment}
                                           type="text"
                                           ref="deskripsi"
                                           id="deskripsi"
                                           name="deskripsi"
                                           className="form-control"/>
                                </div>
                                <div className="feWrapper">
                                    <ul className="myBtnGroup">
                                        <li>
                                            <input onClick={this.onReturnToMain.bind(this)} type="button"
                                                   value="kembali"
                                                   className="btn btn-info"/>
                                        </li>
                                        <li>
                                            <input onClick={this.cancelSave.bind(this)} type="button" value="batal"
                                                   className="btn btn-primary"/>
                                        </li>
                                        <li>
                                            <input type="submit" value="ubah" className="btn btn-info"/>
                                        </li>
                                    </ul>
                                </div>
                            </div>
                            <div className="clearfix"></div>
                        </form>
                    </div>
                    <div class="clearBoth"></div>
                </div>
            </section>
        );
    }
}

这是我在浏览器中运行时的样子:

enter image description here

文本框内的值是先前状态的值,虽然状态正在更新,但在刷新页面之前组件不会重新呈现。

所以请任何人帮助我吗?请帮助我..

问候,

Vidy Hermes

2 个答案:

答案 0 :(得分:1)

只需从输入组件中删除defaultValue即可。 defaultValue将它们变成不受控制的组件。

https://facebook.github.io/react/docs/uncontrolled-components.html#default-values

如果您想更新组件值:

<input
  type="text"
  ref="nama"
  id="nama"
  name="nama"
  className="form-control"
  value={namaDepartment}
/>

<textarea
  type="text"
  ref="deskripsi"
  id="deskripsi"
  name="deskripsi"
  className="form-control"
  value={deskripsiDepartment}
/>

答案 1 :(得分:0)

我不确定是不是这样,但我看到两件可能相关的事情(评论太长了,所以如果它不是解决方案,我会编辑/删除这个答案):
在reducer中,不要改变状态对象,而只是在每个apply plugin: 'com.android.application' allprojects { repositories { jcenter() maven { url "https://maven.google.com" } } } android { compileSdkVersion 26 buildToolsVersion '25.0.3' defaultConfig { applicationId "com.credihealth.android" minSdkVersion 16 targetSdkVersion 26 versionCode 52 versionName "4.2.1.1" } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { debuggable true } } productFlavors { demo { applicationIdSuffix ".demo" } full { applicationIdSuffix ".full" } } } repositories { mavenCentral() flatDir { dirs 'libs' } } dependencies { compile(name: "youtube_player_api", ext: "jar") // this line must be included to integrate with Firebase // this line must be included to use FCM compile 'com.android.support:appcompat-v7:26.0.1' compile 'com.android.support:design:26.0.1' compile 'com.android.support:recyclerview-v7:26.0.1' compile 'com.android.support:palette-v7:26.0.1' compile 'com.android.support:cardview-v7:26.0.1' compile 'com.squareup.retrofit:retrofit:1.9.0' compile 'com.squareup.okhttp:okhttp:2.3.0' compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.4' compile 'com.roomorama:caldroid:2.2.1' compile 'com.facebook.android:facebook-android-sdk:4.7.0' compile 'com.uncopt:android.justified:1.0' compile 'com.yayandroid:LocationManager:2.0.3' compile 'com.google.android.gms:play-services-plus:11.0.1' compile 'com.google.android.gms:play-services-location:11.0.1' compile 'com.google.android.gms:play-services-auth:11.0.1' compile 'com.google.android.gms:play-services-analytics:11.0.1' compile 'com.google.android.gms:play-services-maps:11.0.1' compile 'com.hbb20:ccp:1.7.6' compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' compile 'com.github.aakira:expandable-layout:1.6.0@aar' compile 'com.google.firebase:firebase-core:11.0.1' compile 'com.google.firebase:firebase-messaging:11.0.1' compile 'com.stepstone.stepper:material-stepper:3.3.0' compile 'com.android.support.constraint:constraint-layout:1.0.2' fullCompile 'com.twilio:video-android:1.3.0' } apply plugin: 'com.google.gms.google-services' 块上返回一个新对象:

case

另外,没有必要在export default function (state = { message: null, activeRow: {}, error: false }, action) { switch (action.type) { case "GET_SINGLE_DEPARTMENT": { return { ...state, activeRow: {...action.payload.data}, message: action.payload.success.message, error: false }; } case "GET_SINGLE_DEPARTMENT_FAILED": { return {...state, message: action.payload.error.message, error: true}; } default: return state; } } 中写下这行代码:
constructor我几乎可以肯定它与您的问题无关,但如果您没有填充this.state,那么这不应该存在;