Mithril Mithril - 5 months ago 45
Ajax Question

react-redux initial ajax data and generate childrens

I am new to react-redux.I have to says I read a lot of example project, many use webpack and couple a lot of package together without detailed introduction. I also read official example several times, but I still can not understand it well, specially in

how to get initial data, and show it in the dom
and
communicate with ajax
(not like jquery.ajax, use ajax in redux seems very complex, everyone's code has different approach and different style make it much hard to understand)

I decide to build a file manager webui to learn react-redux.
To begin, I just want it work, so no ajax:

containers/App.js:

import React, { Component, PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import {getFileList} from '../actions/NodeActions'
import Footer from '../components/Footer';
import TreeNode from '../containers/TreeNode';
import Home from '../containers/Home';


export default class App extends Component {

componentDidMount() {
let nodes = getFileList();
this.setState({
nodes: nodes
});
}

render() {
const { actions } = this.props;
const { nodes } = this.state;
return (
<div className="main-app-container">
<Home />
<div className="main-app-nav">Simple Redux Boilerplate</div>
{nodes.map(node =>
<TreeNode key={node.name} node={node} {...actions} />
)}
<Footer />
</div>
);
}
}

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


function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(getFileList, dispatch)
};
}

export default connect(
mapStateToProps,
mapDispatchToProps
)(App);


actions/NodeActions.js:

import { OPEN_NODE, CLOSE_NODE } from '../constants/ActionTypes';

export function openNode() {
return {
type: OPEN_NODE
};
}

export function closeNode() {
return {
type: CLOSE_NODE
};
}

class NodeModel {
constructor(name, path, type, right) {
this.name = name;
this.path = path;
this.type = type;
this.right = right;
}
}

const testNodes = [
new NodeModel('t1','t1', 'd', '777'),
new NodeModel('t2','t2', 'd', '447'),
new NodeModel('t3','t3', 'd', '667'),
]

export function getFileList() {
return {
nodes: testNodes
}
}

export function ansyncGetFileList() {
return dispatch => {
setTimeout(() => {
dispatch(getFileList());
}, 1000);
};
}


reducers/index.js

import { combineReducers } from 'redux';
import opener from './TreeNodeReducer'

const rootReducer = combineReducers({
opener
});

export default rootReducer;


reducers/TreeNodeReducer.js

import { OPEN_NODE, CLOSE_NODE } from '../constants/ActionTypes';

const initialState = [
{
open: false
}
]

export default function opener(state = initialState, action) {
switch (action.type) {
case OPEN_NODE:
return true;
case CLOSE_NODE:
return false;
default:
return state;
}
}


reducers/index.js

import { combineReducers } from 'redux';
import opener from './TreeNodeReducer'

const rootReducer = combineReducers({
opener
});

export default rootReducer;


store/store.js(a copy from a redux demo):

import { createStore, applyMiddleware, compose } from 'redux';
import rootReducer from '../reducers';
import createLogger from 'redux-logger';
import thunk from 'redux-thunk';
import DevTools from '../containers/DevTools';

const logger = createLogger();

const finalCreateStore = compose(
// Middleware you want to use in development:
applyMiddleware(logger, thunk),
// Required! Enable Redux DevTools with the monitors you chose
DevTools.instrument()
)(createStore);

module.exports = function configureStore(initialState) {
const store = finalCreateStore(rootReducer, initialState);

// Hot reload reducers (requires Webpack or Browserify HMR to be enabled)
if (module.hot) {
module.hot.accept('../reducers', () =>
store.replaceReducer(require('../reducers'))
);
}

return store;
};


chrome console says:
Uncaught TypeError: Cannot read property 'nodes' of null
at
App render() {


I don't know the es6 well, due to react-redux strange syntax make me read the es6 doc, but I am not sure my code is right.

Tring:


  1. I think maybe can not create
    testNodes
    with
    new
    instance in the list, so I change
    testNodes
    to plain json:

    const testNodes = [
    {name:'t1',type:'t1'},
    {name:'t2',type:'t2'},
    {name:'t3',type:'t3'},
    ]

    Still same error

  2. maybe action can not get the global
    testNodes
    ? I move
    testNodes
    into
    getFileList
    , not work too.



I have no idea.
After solve this, I would try to replace
getFileList
content to a ajax call.

PS:My react-route also have strange problem, chrome show blank page and no error when I wrap
App
with route, just feel react-redux is so hard for newbee...this is just some complain...

Answer

Simply

  1. you don't need to bindActionCreators yourself
  2. you need to use this.props.getFileList
  3. you don't need to manage it with component's state

for eg.

import {ansyncGetFileList} from '../actions/NodeActions'

componentWillMount() {
  // this will update the nodes on state
  this.props.getFileList();  
}

render() {
  // will be re-rendered once store updated
  const {nodes} = this.props;
  // use nodes 
}

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

export default connect(
  mapStateToProps,
  { getFileList: ansyncGetFileList }
)(App);

Great Example

Comments