2017-12-12 19 views
1

背景の発送を上書きしない方法:私はReact/Reduxのアイデアを実践しています
を。私はデータの流れに従いたいと思っています。
axiosディスパッチはaction - propsに>減速SETSTATE - >コンポーネントrender()ブランク状態で

問題は、1つの以上の点であってもよいです。私はFrontend世界には初めてです。 (必要な場合)

問題私のアプリを再設計すること自由に感じなさい:this.props.companiesが空白になっているので、
会社が出てレンダリングされませんが。しかし、axiosは、バックエンドから配列を取得します。

action/index.js

//First experiment action returns promise instance 
export function fetchCompanies(token) { 
    const jwtReady = 'JWT '.concat(token); 
    const headers = { 
    'Content-Type': 'application/json', 
    'Authorization': jwtReady 
    }; 
    const instance = axios({ 
    method: 'GET', 
    url: `${ROOT_URL}/api/companies/`, 
    headers: headers 
    }); 
    return { 
    type: FETCH_COMPANIES, 
    payload: instance 
    } 
} 

export function getCompanies(token){ 
    const jwtReady = 'JWT '.concat(token); 
    const headers = { 
    'Content-Type': 'application/json', 
    'Authorization': jwtReady 
    }; 
    const instance = axios({ 
    method: 'GET', 
    url: `${ROOT_URL}/api/companies/`, 
    headers: headers 
    }); 
    return instance 
    .then(data=> store.dispatch('GET_COMPANIES_SUCCESS', data)); 
} 

company_reducers.js

import {FETCH_COMPANIES, GET_COMPANIES_ERROR, GET_COMPANIES_SUCCESS} from "../actions/const"; 


export default function (state = {}, action) { 
    switch (action.type) { 
    case GET_COMPANIES_SUCCESS: 
     return { 
     ...state, 
     companies: action.payload 
     }; 
    case GET_COMPANIES_ERROR: 
     return { 
     ...state, 
     err_msg: action.payload.text 
     }; 
    default: 
     return state; 
    } 
} 

reducers/index.js

import {combineReducers} from 'redux'; 
import {reducer as formReducer} from 'redux-form'; 
import LoginReducer from './login_reducers'; 
import CompanyReducer from './company_reducers'; 

const rootReducer = combineReducers({ 
    login: LoginReducer, 
    companies: CompanyReducer, 
    form: formReducer 
}); 

export default rootReducer; 

component/select_teams.js

import _ from 'lodash'; 
import React, {Component} from 'react'; 
import {connect} from 'react-redux'; 
import {bindActionCreators} from 'redux'; 
import {fetchCompanies, getCompanies} from "../actions"; 
import {Link} from 'react-router-dom'; 

class SelectTeam extends Component { 
    constructor(props) { 
    super(props); 
    const token = localStorage.getItem('token'); 
    this.state = { 
     token, 
     companies: null, 
     err_msg: null 
    } 
    } 

    componentWillMount() { 
    const tmp = this.props.getCompanies(this.state.token); 
    tmp.then(res => { 
     console.log(res) 
     }) 
     .catch(err => { 
     console.log(err); 
     }) 
    }; 

    renderErrors() { 
    return (
     <div>{this.state.err_msg}</div> 
    ); 
    } 

    renderCompanies() { 
    return _.map(this.props.companies, company => { 
     return (
     <li className="list-group-item" key={company.id}> 
      <Link to={`/${company.id}`}> 
      {company.name} 
      </Link> 
     </li> 
    ) 
    }); 
    } 

    render() { 
    if (this.props.companies === null) { 
     return (
     <div>Loading...</div> 
    ); 
    } 
    console.log(this.props); 

    return (
     <div> 
     <h3>&#10084; Select Team &#10084;</h3> 
     {this.renderErrors()} 
     {this.renderCompanies()} 
     </div> 
    ); 
    } 
} 

function mapStateToProps(state){ 
    return {companies: state.companies} 
} 

function mapDispatchToProps(dispatch) { 
    return bindActionCreators({ 
    fetchCompanies: fetchCompanies, 
    getCompanies: getCompanies 
    }, dispatch); 
} 

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

App.js

import React, {Component} from 'react'; 
import './App.css'; 
import SelectTeam from "./components/select_teams"; 
import reducers from './reducers/index'; 
import {Provider} from 'react-redux'; 
import promise from "redux-promise"; 
import {applyMiddleware, createStore} from 'redux'; 
import {BrowserRouter, Route, Switch, Redirect} from 'react-router-dom'; 
import LoginPage from './components/loginPage'; 

const createStoreWithMiddleware = applyMiddleware(promise)(createStore); 

const PrivateRoute = ({component: Component, isAuthorized, ...otherProps}) => (
    <Route 
    {...otherProps} 
    render={props => (
     isAuthorized() ? (<Component {...props} />) : 
     (
      <Redirect to={ 
      { 
       pathname: '/login', 
       state: {from: props.location}, 
      } 
      } 
      /> 
     ) 
    )} 
    /> 
); 

function PageNotFound() { 
    return (
    <div>404 Page Not Found</div> 
); 
} 

// TODO: I will add RESTful validation with backend later 
function hasToken() { 
    const token = localStorage.getItem('token'); 
    const isAuthenticated = !((token === undefined) | (token === null)); 
    return isAuthenticated; 
} 

export const store = createStoreWithMiddleware(reducers); 

class App extends Component { 
    //I will add security logic with last known location later. 
    //Get the features done first 
    render() { 
    return (
     <Provider store={store}> 
     <BrowserRouter> 
      <div> 
      <Switch> 
       <PrivateRoute exact path="/select-teams" isAuthorized={hasToken} component={SelectTeam}/> 
       <Route path="/login" component={LoginPage}/> 
       <Route component={PageNotFound}/> 
      </Switch> 
      </div> 
     </BrowserRouter> 
     </Provider> 
    ); 
    } 
} 

export default App; 
+0

第1の解決策です。これは 'action'を使用するのではなく、' setState'を行うための単純な 'callback'を試みます。しかし、それは私が望む 'React'フローではありません。 – Sarit

+0

サーバーからデータを受け取ったときにアクションをディスパッチしていません。 – ram1993

+0

@ ram1993ヒントが正しいです。私はそれを派遣しなければならない。今私は 'Redux-Thunk'に従います。ご回答いただきありがとうございます。 – Sarit

答えて

1

は、サーバーから取得したデータとアクションを派遣すべきです。 アクションはオブジェクトを返す純粋な関数です(オブジェクトには少なくともTYPEフィールドがあります)。 非同期操作がある場合は、関数を返すアクション作成者であるRedux-Thunkを使用し、その内部でAPIフェッチを呼び出します。あなたのcompany_reducers.js

// Company Reducer Function, State here represents only the companies part of the store 
case FETCH_COMPANIES_SUCCESS: // should match the the type returned by the action 
    return [ 
     ...state, 
     ...action.data 
    ] 
// other cases & default 

// imports.. 
export const fetchCompaniesSuccess = (data) => { 
    retyrn { 
     type: FETCH_COMPANIES_SUCCESS, 
     data 
    } 
} 


export const fetchCompanies = (token) => dispatch => { 
    // ... 
    axios(...).then(dispatch(data => fetchCompaniesSuccess(data))) 
} 

手順についてはRedux-Thunkドキュメントを読んで、あなたのcreateStoreにおけるミドルウェアとしてredux-thunkを追加してください:ここで

actionsスニペットがあります。あなたの中に、その後

コンポーネント:企業データはReduxのストアに追加されると

componentDidMount(){ 
    this.props.fetchCompanies(this.state.token); 
} 

、コンポーネントが再描画されますとcompanies配列は、あなたが重複companiesを持っている必要はありませんprops で利用できるようになります配列をコンポーネント状態にします。

あなたはDan Abramov introduction to reduxを見たいかもしれませんが、それは無料のコースです。

+0

しばらくお待ちください。私はちょうど 'Redux-Thunk'に焦点を当て始めます。 – Sarit

+0

私はここで新たな疑問を提起しています。 https://stackoverflow.com/questions/47767231/how-to-add-redux-thunk-to-existing-store – Sarit

+0

ありがとうございました。あなたは私にとって重要なパズルを提供します。 – Sarit

0

あなたのdispatchの構文が間違っているようです。パラメータは、型とペイロードを持つオブジェクトでなければなりません。

return instance 
    .then(data=> store.dispatch({ 
     type: 'GET_COMPANIES_SUCCESS', 
     payload: data 
    })); 
+0

ありがとうございました。しかし、「Redux-Thunk」は私の問題を完全に解決します。 – Sarit

関連する問題