我正在努力学习React-Redux。我正在创建一个简单的应用程序,从Teleport API获取数据并根据用户的输入显示列表。
我的问题是,即使在容器组件中调度了操作,状态也不会更改,结果也不会显示。
这是两次调度操作后控制台的屏幕截图。
我认为正确存储数据存在问题。如果你能帮助我,我感激不尽。
这是我的代码。
/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'));
答案 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;
}