如何不用空白状态覆盖调度

时间:2017-12-12 04:41:52

标签: javascript reactjs axios

背景
我正在实践React/Redux的想法。我想跟随数据流。
axios发送action - > reducer setState to props - >组件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;

2 个答案:

答案 0 :(得分:1)

您应该使用从服务器获取的数据调度操作。 动作是返回对象的纯函数(该对象至少具有TYPE字段)。 如果您有任何异步操作,可以使用Redux-Thunk,它是一个返回函数的动作创建者,并在其中调用api fetch。

以下是actions代码段:

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


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

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

确保redux-thunk中添加createStore作为中间件,请阅读Redux-Thunk doc说明。

然后在你的组件中:

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

将公司数据添加到redux商店后,您的组件将重新呈现,companies数组将在props中可用 您不需要在组件状态中具有重复的companies数组。

您可能需要观看Dan Abramov introduction to redux,这是免费课程。

答案 1 :(得分:0)

好像你的dispatch语法错了。参数应该是具有类型和有效负载的对象。

picasso