简体   繁体   English

减速器未正确更改React-Redux Store

[英]React-Redux Store is not properly changed by reducer

I'm struggling to learn React-Redux. 我正在努力学习React-Redux。 I'm making a simple application that fetch data from Teleport API and show the list according to the user's input. 我正在制作一个简单的应用程序,该应用程序从Teleport API获取数据并根据用户的输入显示列表。

My issue is that even though action is dispatched in container component, state is not changed and the result does not show up. 我的问题是,即使在容器组件中分派了动作,状态也不会更改并且结果不会显示。

This is a screenshot of console after dispatching action twice. 这是两次调度操作后控制台的屏幕截图。

在此处输入图片说明

I suppose that there is an issue to store data properly. 我认为存在正确存储数据的问题。 I appreciate if you can help me. 谢谢您的帮助。

Here is my code. 这是我的代码。

/container/search.js /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 /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 /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 /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 //编辑// 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'));

You can use redux api middleware to do the api call.All you have to change is 您可以使用redux api中间件进行api调用。您需要更改的只是

actions/index.js 动作/ 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 /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 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 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'))

Note: you can install Redux devtools extension in chrome and u can check the redux store in your chrome developer tools.I think this will be easy to find out what happens in your redux store. 注意:您可以在chrome中安装Redux devtools扩展,您可以在chrome开发人员工具中检查redux存储。我认为这很容易找出您的redux存储中发生了什么。

Since axios.get(url) is asynchronous you need to wait for the request to succeed and then then dispatch an action. 由于axios.get(url)是异步的,因此您需要等待请求成功,然后分派操作。 You could make use of middlewares such as redux-thunk while creating a store and then do the following 您可以在创建商店时使用诸如redux-thunk之类的中间件,然后执行以下操作

/actions/index.js /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 /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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM