简体   繁体   English

Redux - 调度后应用程序不会重新渲染

[英]Redux - the app does not re-render after dispatching

I'm new to react + redux. 我刚接触+ redux。 I encountered a problem which my app is not re-render when I dispatch an action. 我遇到了一个问题,当我发送一个动作时,我的应用程序没有重新渲染。 However, I use getState() to examine the state, it did change. 但是,我使用getState()来检查状态,它确实发生了变化。 I look up documents but still have no idea what the problem is. 我查阅文档但仍然不知道问题是什么。 Please help me, thanks. 请帮帮我,谢谢。

The code is as below 代码如下

====actions.js==== ==== actions.js ====

export const ADD_MAIL = 'ADD_MAIL';
export const DEL_MAIL = 'DEL_MAIL';

export function addMail(email) {
    return {
        type: ADD_MAIL,
        email
    }
}

export function delMail(id) {
    return {
        type: DEL_MAIL,
        id
    }
}

====reducers.js==== ==== reducers.js ====

import { combineReducers } from 'redux'
import { ADD_MAIL, DEL_MAIL } from '../actions/actions'
import MAILS from '../data'

function emails(state = MAILS, action) {
    switch (action.type) {
        case ADD_MAIL: 
            console.log("ADD_MAIL");

            return [
                action.email, 
                ...state
            ];

        case DEL_MAIL:
            let idx = state.length;
            let i = 0;

            // Find the target mail
            while(idx--) {
                if (state[idx] && state[idx].serialNo === action.id)
                    i = idx;
            }

            let arr1 = state.slice(0, i); 
            let arr2 = state.slice(i + 1);

            let newList = arr1.concat(arr2);

            console.log("DEL_MAIL");
            return newList;

        default: 
            return state;
    }
}

const rootReducer = combineReducers({
  emails
});

export default rootReducer;

====main.js==== ==== main.js ====

import React from 'react'
import { render } from 'react-dom'
import { Link } from 'react-router'
import { connect } from 'react-redux'
import { createStore } from 'redux'
import { addMail, delMail } from './actions/actions'
import rootReducer from './reducers/reducers'
import * as btn from './module/button'
import * as module from './module/module'


var store = createStore(rootReducer);

class Inbox extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            searchText: ''
        }
        this.handleUserInput = this.handleUserInput.bind(this);
        this.deleteMail = this.deleteMail.bind(this);
        this.sendMail = this.sendMail.bind(this);
    }

    handleUserInput(searchText) {
        this.setState({
            searchText: searchText
        });
    }

    deleteMail(obj) {
        store.dispatch(delMail(obj.serialNo));
        console.log(store.getState()); 
        // This displays the correct new state in console after dispatch
    }

    sendMail(newMail) {
        store.dispatch(addMail(newMail));
        console.log(store.getState());
        // This displays the correct new state in console after dispatch
    }

    render() {
        let mails = [];
        let search = this.state.searchText.toUpperCase();

        let emails = this.props.emails;
        emails.map(mail => {
            if (mail.from.toUpperCase().indexOf(search) !== -1)
                mails.push(mail);
        });

        let sender = (mails.length === emails.length) ? "all" : this.state.searchText;

        return (
            <div className="main">
                <div className="toolbar">
                    <span>You have {mails.length} message from {sender}.</span>
                    <module.SearchInput searchText={this.state.searchText} onUserInput={this.handleUserInput} />    
                    <div className="functions">
                        <btn.AddButton />
                    </div>  
                </div>

                <div className="mailList">
                    {mails.map(mail => (
                        <div className="item" key={mail.serialNo}>
                            <div className="info sender">
                                From: {mail.from}
                            </div>
                            <div className="info date">
                                {mail.date}
                            </div>
                            <div className="info subject">
                                Subject: {mail.subject}
                            </div>
                            <div className="functions">
                                <btn.ReadButton serialNo={mail.serialNo} />
                                <btn.DeleteButton serialNo={mail.serialNo} deleteMail={this.deleteMail} />
                            </div>
                        </div>
                    ))}
                </div>

                <module.NewMailInput sendMail={this.sendMail} />
            </div>
        );
    }
}

function mapStateToProps(state) {
    return {
        emails: state.emails
    };
}

export default connect(mapStateToProps)(Inbox);

====app.js==== ==== app.js ====

import React from 'react'
import { render } from 'react-dom'
import { Router, Route, IndexRoute, browserHistory } from 'react-router'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { Menu } from './menu'
import { Mail } from './main'
import Inbox from './main'
import rootReducer from './reducers/reducers'

var store = createStore(rootReducer);

class App extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div style={{height: '100%'}}>
                <Menu />
                {this.props.children}
            </div>
        );
    }
}

class Home extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <Inbox />
        );
    }
}

render(
    <Provider store={store}>
        <Router history={browserHistory}>
            <Route path="/" component={App}>
                <IndexRoute component={Home} />
                <Route path="/inbox" component={Inbox} />
                <Route path="/message/:mailSerial" component={Mail} />
            </Route>
        </Router>
    </Provider>, 
document.getElementById('app-container'))

In your main.js file, you have made a Inbox component. 在main.js文件中,您创建了一个Inbox组件。 That is a React Component but not a Redux Component. 这是一个React组件,但不是Redux组件。

You have to do something like this while exporting Inbox component. 导出Inbox组件时,您必须执行类似的操作。

module.exports = connect((store)=> {
    return {emails: store.emails}
})(Inbox) 

You have 2x stores: one in main.js and one in app.js . 你有2个店:一个在main.js ,一个在app.js Remove the one in main.js and update the calls to dispatch to use the one passed as props: 删除main.js中的main.js并更新对dispatch的调用以使用作为props传递的调用:

class Inbox extends React.Component {
    ...

    deleteMail(obj) {
        this.props.dispatch(delMail(obj.serialNo));
    }

    ...
}

Try this: 尝试这个:

import React from 'react'
import { render } from 'react-dom'
import { Link } from 'react-router'
import { connect } from 'react-redux'
import { addMail, delMail } from './actions/actions'
import * as btn from './module/button'
import * as module from './module/module'

class Inbox extends React.Component {
    constructor(props) {
    super(props);
    this.state = {
      searchText: ''
    }
    this.handleUserInput = this.handleUserInput.bind(this);
    this.deleteMail = this.deleteMail.bind(this);
    this.sendMail = this.sendMail.bind(this);
  }

  handleUserInput(searchText) {
    this.setState({
      searchText: searchText
    });
  }

  deleteMail(obj) {
    this.props.delMail(obj.serialNo); //Call the delMail action
    console.log(store.getState());
  }

  sendMail(newMail) {
    this.props.addMail(newMail); //Call the addMail action
    console.log(store.getState());
  }

  render() {
    let mails = [];
    let search = this.state.searchText.toUpperCase();

    let emails = this.props.emails;
    emails.map(mail => {
      if (mail.from.toUpperCase().indexOf(search) !== -1)
        mails.push(mail);
    });

    let sender = (mails.length === emails.length) ? "all" : this.state.searchText;

    return (
      <div className="main">
        <div className="toolbar">
          <span>You have {mails.length} message from {sender}.</span>
          <module.SearchInput searchText={this.state.searchText} onUserInput={this.handleUserInput} />    
          <div className="functions">
            <btn.AddButton />
          </div>  
        </div>

        <div className="mailList">
            {
            mails.map(mail => (
                <div className="item" key={mail.serialNo}>
                    <div className="info sender">From: {mail.from}</div>
                    <div className="info date">{mail.date}</div>
                    <div className="info subject">Subject: {mail.subject}</div>
                    <div className="functions">
                        <btn.ReadButton serialNo={mail.serialNo} />
                        <btn.DeleteButton serialNo={mail.serialNo} deleteMail={this.deleteMail} />
                    </div>
                </div>
            ))
          }
        </div>
          <module.NewMailInput sendMail={this.sendMail} />
      </div>
        );
    }
}

function mapStateToProps(state) {
    return {
      emails: state.emails
    }; 
}

//Connect the component to re-render when state change and 
// makes the emails and actions to be available through this.props
export default connect(mapStateToProps, {delMail, addMail})(Inbox);



//To connect Mail component which I suppose that is in another file
function mapStateToProps(state) { 
    return { emails: state.emails };
}
export default connect(mapStateToProps, {})(Mail);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM