简体   繁体   中英

React-redux code does not drive a re-render of the react component upon a successful redux dispatch and successful reducer

The following code works, but does not re-drive the app render() upon a successful redux dispatch call. I cannot see what is wrong. There is mocked up data here I put in to simplify things trying to debug this rudimentary problem.

What works:

  1. The app react component renders the first time
  2. The dispatcher successfully invokes the reducer
  3. The reducer successfully invokes the mapStateToProps() with the correct state change data

What fails:

  1. The app re-render is never invoked upon the successful dispatch/reducer state change

index.js

import { createStore } from 'redux';
import { Provider } from 'react-redux';
import ReactDOM from 'react-dom';
import './css/index.css';
import App from './containers/App';
import reducer from './reducers';


const store = createStore(
  reducer,
  {schooldata: {}}
)

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

store.dispatch({type: "LOAD_SCHOOL_DATA"});

containers/App.js

import React from 'react';
import { connect, Provider } from 'react-redux';
import {
  Route,
  NavLink,
  BrowserRouter as Router,
  Switch,
} from 'react-router-dom';
import Home from "../components/Home";
import Photos from "../components/Photos";
import Attendees from "../components/Attendees";

class App extends React.Component {

  constructor(props) {
    super(props);
  }

  componentDidMount() {
    
  };

  render() {
    console.log("App is rendering...");
    console.log("Props in app: %s", JSON.stringify(this.props));
    const src=`${this.props.images}/pic.jpg`;
    console.log("src: %s", src);

    return (
      <div>
        <Router>
      <div>
        <ul>
          <li>
            <NavLink exact activeClassName="active" to="/">
              Home
            </NavLink>
          </li>
          <li>
            <NavLink activeClassName="active" to="/photos">
              Photos
            </NavLink>
          </li>
          <li>
            <NavLink activeClassName="active" to="/attendees">
              Attendees
            </NavLink>
          </li>
        </ul>
        <hr />
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/photos" component={Photos} />
          <Route path="/attendees" component={Attendees} />
        </Switch>
      </div>
    </Router>
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  console.log("Mapping this: %s", JSON.stringify(state));
  return (state.schooldata);
}


const mapDispatchToProps = function (dispatch) {
  console.log("Mapping dispatch to props");
  return({});
}


export default connect(mapStateToProps)(App);

reducers/index.js

import axios from 'axios';
import { combineReducers } from 'redux';
import { LOAD_SCHOOL_DATA, ADD_PHOTO, ADD_ATTENDEE } from '../constants/ActionTypes';

const routeAction = (state, action) => {
    console.log("routeAction: %s", JSON.stringify(action));
    switch(action.type) {
        case LOAD_SCHOOL_DATA:
            console.log("Action type match.");
            return ({
                schooldata: {images:"blah", photos:"bleep"},
              });
        case ADD_PHOTO:
            return addPhoto(state);
        case ADD_ATTENDEE:
            return addAttendee(state);
        default:
            return {};
    }
}


const loadSchoolData = async () => {
    await axios.get("/schooldata").then((response) => {
        console.log("School data from server: %s", JSON.stringify(response.data));
        return(response.data);
    })
}

const addPhoto = (state) => {
    return state.loadSchoolData.photoList
}

const addAttendee = (state) => {

}

export default combineReducers({
    routeAction
});

Browser debug output

routeAction: {"type":"@@redux/INITx.t.b.e.s"} index.js:6:12
routeAction: {"type":"@@redux/PROBE_UNKNOWN_ACTION0.c.1.k.j.c"} index.js:6:12
routeAction: {"type":"@@redux/INITx.t.b.e.s"} index.js:6:12
Mapping this: {"routeAction":{}} App.js:64:10
App is rendering... App.js:24:12
Props in app: {} App.js:25:12
src: undefined/pic.jpg App.js:27:12
props: {"history":{"length":2,"action":"POP","location":{"pathname":"/","search":"","hash":""}},"location":{"pathname":"/","search":"","hash":""},"match":{"path":"/","url":"/","isExact":true,"params":{}}} Home.js:15:12
routeAction: {"type":"LOAD_SCHOOL_DATA"} index.js:6:12
Action type match. index.js:9:20
Mapping this: {"routeAction":{"schooldata":{"images":"blah","photos":"bleep"}}} App.js:64:10
routeAction: {"type":"LOAD_SCHOOL_DATA"} index.js:6:12
Action type match. index.js:9:20
Mapping this: {"routeAction":{"schooldata":{"images":"blah","photos":"bleep"}}} App.js:64:10
routeAction: {"type":"LOAD_SCHOOL_DATA"} index.js:6:12
Action type match. index.js:9:20
Mapping this: {"routeAction":{"schooldata":{"images":"blah","photos":"bleep"}}} App.js:64:10

Found the problem. mapStateToProps(), in App.js, was not returning a valid key in the state JSON structure, thus, the component's props were not changing. This means it's not really the state change that drives a re-rendering of the component, it's its props change that does. This is what fixed this little mock up:

App.js

const mapStateToProps = (state, props) => {
  console.log("Mapping this: %s", JSON.stringify(state));
  return (state.routeAction);  // Return valid key!
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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