Reducer没有正确更改React-Redux Store

时间:2017-11-14 09:59:51

标签: javascript reactjs redux react-redux

我正在努力学习React-Redux。我正在创建一个简单的应用程序,从Teleport API获取数据并根据用户的输入显示列表。

我的问题是,即使在容器组件中调度了操作,状态也不会更改,结果也不会显示。

这是两次调度操作后控制台的屏幕截图。

enter image description here

我认为正确存储数据存在问题。如果你能帮助我,我感激不尽。

这是我的代码。

/container/search.js

class Search extends Component{
 constructor(props){
    super(props);
    this.state = {
      city : ""
    }
   this.handleSubmit = this.handleSubmit.bind(this);
   this.handleChange = this.handleChange.bind(this);
   }

handleChange(event) {
    console.log(event.target.value)
    this.setState({
        city: event.target.value
    });
}

handleSubmit(event){
    event.preventDefault();
    console.log(this.state.city)
    this.props.addData(this.state.city);
    this.setState({
        city: ""
    });
}
render(){
    return(
        <div>
        <form onSubmit={this.handleSubmit}>
        <input type="text"
               placeholder="add city name"
               onChange={this.handleChange}
               value={this.state.city} />
        <button>Submit</button>
        </form>
        </div>
        )
}
}

function mapDispatchToProps(dispatch) {
return bindActionCreators({ addData }, dispatch);
}

export default connect(null, mapDispatchToProps)(Search);

/actions/index.js

import axios from 'axios';

const ROOT_URL = "https://api.teleport.org/api/cities/?search";

const ADD_DATA = 'ADD_DATA';

export function addData(city){
    const url = `${ROOT_URL}=${city}`;
    const request = axios.get(url);
    return {
        type: ADD_DATA,
        payload: request
    };
 }

/reducers/reducer_data.js

import { ADD_DATA } from "../actions/index";

export default function( state=[], action) {
switch(action.type) {
    case ADD_DATA:
        return [action.payload.data, ...state];
}
return state;
}

/reducers/index.js

import { ADD_DATA } from "../actions/index";

export default function( state=[], action) {
    switch(action.type) {
        case ADD_DATA:
            return [action.payload.data, ...state];
}
return state;
}

// EDIT // index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import promiseMiddleware from 'redux-promise';
import logger from 'redux-logger'

import reducers from './reducers';
import Search from './containers/search';

const createStoreWithMiddleware = applyMiddleware(promiseMiddleware, logger)(createStore);

ReactDOM.render(
    <Provider store={createStoreWithMiddleware(reducers)}>
    <Search />
    </Provider>
, document.querySelector('.container'));

2 个答案:

答案 0 :(得分:1)

您可以使用redux api中间件来进行api调用。您需要更改的是

动作/ index.js

import {CALL_API} from 'redux-api-middleware';


export const addData=(city)=>({

    [CALL_API]:{

        endpoint:"https://api.teleport.org/api/cities",
        query:{
              "search":city
             }
        method:'GET',
        types:["ADD_DATA","ADD_DATA_SUCCESS","ADD_DATA_FAILURE"]
    }
    });

/reducers/reducer_data.js

           import {combineReducers} from 'redux'
                const InitialData={
                    dataList:[],
                    error:null,
                    loading:false
                }
                export const dataList=(state=InitialData,action)=>{
                    switch(action.type){
                        case "ADD_DATA":
                            return Object.assign({},state,{
                                dataList:[],error:null,loading:true
                            })
                        case "ADD_DATA_SUCCESS":
                            return Object.assign({},state,{
                                dataList:action.payload,error:null,loading:false
                            })
                        case "ADD_DATA_FAILURE":
                           error = action.payload.data || { message: action.payload };
                            return Object.assign({},state,{
                                dataList:action.payload,error:error,loading:false
                            })
                        default:
                            return state;
                    }
                }

            //Its better to use combine reducer to combine all the reducers 
            //you have in your app  as one as redux permits only one store per app  


            export const reducers=combineReducers({
            DataList:dataList
            })

export default reducers

store.js

import {
  applyMiddleware,
  createStore,compose
} from 'redux';

// import thunk from 'redux-thunk';
import { apiMiddleware } from 'redux-api-middleware';
import {CALL_API} from 'redux-api-middleware';
import promise from 'redux-promise';
import reducers from './reducer';
import { logger} from 'redux-logger'; 
import ReduxThunk from 'redux-thunk' 

import qs from 'querystring'



 function queryMiddleware() {
  return next => action => {
    if (action.hasOwnProperty(CALL_API) && action[CALL_API].hasOwnProperty('query')) {
      const request = action[CALL_API];
      request.endpoint = [
        request.endpoint.replace(/\?*/, ''),
        qs.stringify(request.query),
      ].join('?');
      delete request.query;

      return next({ [CALL_API]: request });
    }

    return next(action);
  };
}
export function ConfigureStore(IntitialState={}){
    const stores=createStore(reducers,IntitialState,compose(
        applyMiddleware(queryMiddleware,ReduxThunk,apiMiddleware,promise),
         window.devToolsExtension ? window.devToolsExtension() : f => f
        ));


    return stores;
}; 
 export const  store=ConfigureStore()

index.js

import React from 'react'
import  ReactDOM from 'react-dom'
import store from './store'
import Search from './Search'
ReactDOM.render((
     <Provider store={store}>
            <Search />
        </Provider>
    ),document.getElementById('main-container'))

注意:你可以在chrome中安装Redux devtools扩展,你可以在你的chrome开发工具中查看redux商店。我想这很容易找出你的redux商店会发生什么。

答案 1 :(得分:0)

由于axios.get(url)是异步的,您需要等待请求成功,然后再分派一个动作。您可以在创建商店时使用redux-thunk等中间件,然后执行以下操作

/actions/index.js

const ADD_DATA = 'ADD_DATA';

export function addData(city){

    return function(dispatch) {
         const url = `${ROOT_URL}=${city}`;
         axios.get(url)
               .then((res) => {
                    dispatch({
                       type: ADD_DATA,
                       payload: res.data
                    });
               });
    }

 }

/reducers/index.js

import { ADD_DATA } from "../actions/index";

export default function( state=[], action) {
    switch(action.type) {
        case ADD_DATA:
            return [...state, action.payload];
}
return state;
}