2016-06-20 2 views
1

Я новичок в реакции-редукции. Должен сказать, что я читал много примеров проекта, многие используют веб-пакет и объединяют много пакетов без подробного введения. Я также читаю официальный пример несколько раз, но я все еще не могу понять это хорошо, особенно в how to get initial data, and show it in the dom и communicate with ajax (не как jquery.ajax, использование ajax в редуксе кажется очень сложным, каждый код имеет разный подход и отличается стилем, понять)initial ajax-response-redux и генерировать детей

Я решил построить файловый менеджер webui, чтобы узнать, как реагировать-редукция. Чтобы начать, я просто хочу работать, так что не Аякса:

контейнеры/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); 

действия/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); 
    }; 
} 

редукторы/index.js

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

const rootReducer = combineReducers({ 
    opener 
}); 

export default rootReducer; 

редукторы/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; 
    } 
} 

редукторы/index.js

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

const rootReducer = combineReducers({ 
    opener 
}); 

export default rootReducer; 

магазин/store.js (копия из Redux демо):

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; 
}; 

хром консоль говорит: Uncaught TypeError: Cannot read property 'nodes' of nullApp render() { на

Я не знаю es6 хорошо, из-за странного синтаксиса react-redux заставляю меня читать документ es6, но я не уверен, что мой код прав.

Tring:

  1. Я думаю, что, может быть, не может создать testNodes с new, например, в списке, так что я изменить testNodes в обычный формат JSON: const testNodes = [ {name:'t1',type:'t1'}, {name:'t2',type:'t2'}, {name:'t3',type:'t3'}, ] Еще та же ошибка

  2. возможно действие не может получить глобальный testNodes? Я перемещаю testNodes в getFileList, но не работаю.

Я понятия не имею. После решения этого вопроса я попытался бы заменить содержимое getFileList на вызов ajax.

PS: У меня также есть странная проблема, хром показывает пустую страницу и никаких ошибок при обертке App с маршрутом, просто чувствуйте, что реакция-редукция так тяжела для новичков ... это всего лишь жалоба ...

+0

Вы можете показать нам, как вы настроили хранилище с помощью редуктора? –

+0

@ code-jaff Я думаю, что магазин и редуктор не очень сильно относятся к этому вопросу, поэтому не ставьте их, чтобы сделать свежий вид. Теперь я добавляю код к вопросу. – Mithril

ответ

3

Просто

  1. Вам не нужно bindActionCreators себя
  2. вам нужно использовать this.props.getFileList
  3. вам не нужно управлять его состоянием компонента

например, для.

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

Обновления на основе обновления вопроса и комментарии

  1. поскольку ваше состояние дерево не имеет карты для узлов вы должны иметь это в государстве корень или opener под дерево.
  2. для операции async вам нужно будет изменить свой создатель действия thunk , например.

    export function ansyncGetFileList() { 
        return dispatch => { 
        setTimeout(() => { 
         dispatch({ type: 'NODES_SUCCESS', nodes: getFileList()}); // might need to export the type as constant 
        }, 1000); 
        }; 
    } 
    
  3. обрабатывать тип NODES_SUCCESS действий в редукторе

    const initialState = { 
        nodes: [] 
    }; 
    export default function nodes(state = initialState, action) { 
        switch (action.type) { 
        // ... 
        case 'NODES_SUCCESS': 
        let nodes = state.nodes.slice(); 
        return nodes.concat(action.nodes); 
        // ... 
        } 
    } 
    
  4. используют узлы редуктор для управления узлами суб дерева например, для.

    import { combineReducers } from 'redux'; 
    import opener from './TreeNodeReducer' 
    import nodes from './nodes' 
    
    const rootReducer = combineReducers({ 
        opener, nodes 
    }); 
    
    export default rootReducer; 
    
  5. использование mapStateToProps, как описано выше, чтобы получить узлы

  6. относительно mapDispatchToProps

    Единственный случай использования bindActionCreators когда вы хотите передать некоторые создатели действий вплоть до компонента, который ISN «Не знаю Redux, и вы не хотите передавать диспетчеру или магазин Redux.

    Поскольку у вас уже есть доступ к dispatch, вы можете позвонить ему напрямую. Передача карты - сокращенная версия. video

+0

Большое спасибо, я никогда не думал, что просто позвоню 'this.props.getFileList();' будет соответствовать моей цели! Но почему мне не нужны 'bindActionCreators'? Я вижу, что многие примеры используют его, а некоторые из них доставляют действия дочернему узлу. – Mithril

+0

О, я понимаю, 'getFileList' в моем коде не является« ActionCreater », поэтому нет необходимости связывать. – Mithril

+0

@ Мифрил обновленный ответ, пожалуйста, проверьте его –