React Redux Thunk 与 Typescript 发出 api 请求
React Redux Thunk with Typescript making api request
我一直在尝试向第三方 API 提出一个简单的 URL 请求。这是我正在处理的项目(https://github.com/JMStudiosJoe/ReactPractice/tree/JMStudiosReact). I have been watching Dan Abramov videos, followed this example from redux docs and this example 并且似乎遗漏了一些小东西,因为日志显示我从 API 收到的数据已被接收并发送到减速器,但由于某种原因状态没有被发送回组件。
以下是代码摘要:
//app.tsx: 从react-redux获取store并使用Provider
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import store from './redux/store/store'
import { Provider } from 'react-redux'
import { getAddressData } from './redux/actions/voteSmartActions'
import {UIRouter, UIView, UISref, UISrefActive, pushStateLocationPlugin} from 'ui-router-react';
import NavigationBarComponent from './components/navigationBarComponent'
store.dispatch(getAddressData(''))
ReactDOM.render(
<Provider store={store}>
<NavigationBarComponent userType='buyer' />
</Provider>,
document.getElementById("root")
);
有问题的组件从 projectsComponent.tsx 文件中加载
if(projectName == 'Vote Smart Locally' ) {
return (
<VoteSmartLocallyComponent />
)
}
//voteSmartLocallyComponent.tsx
import * as React from 'react'
import { connect } from 'react-redux'
import { getAddressData } from '../../redux/actions/voteSmartActions'
import store from "../../redux/store/store"
interface VoteSmartState {
address: string
userAddressData?: any
}
interface VoteSmartProps {
fetchAddressData: any
}
const API_KEY = 'AIzaSyCWhwRupMs7IeE4IrGEgHtT0Nt-IGZnP9E'
const endURL = '&key='+ API_KEY
const baseRepURL = 'https://www.googleapis.com/civicinfo/v2/representatives?address='
const baseElectionsURL = 'https://www.googleapis.com/civicinfo/v2/elections?alt=json&prettyPrint=true'
class VoteSmartLocallyComponent extends React.Component<VoteSmartProps, VoteSmartState> {
constructor(props) {
super(props)
console.log(props)
this.state = {
address: '',
userAddressData: {}
}
}
removeSpacesAddPluses() {
return this.state.address.split(' ').join('+')
}
lookupAddress(event: React.MouseEvent<HTMLButtonElement>) {
event.preventDefault()
const address = this.removeSpacesAddPluses()
const fullRepURL = baseRepURL + address + endURL
const fullElectionsURL = baseElectionsURL + address + endURL
this.props.fetchAddressData(fullRepURL)
/*
store.subscribe(this.render)
store.dispatch({
type: 'LOOKUP_ADDRESS',
payload: address
})
*/
}
handleAddress(event: React.ChangeEvent<HTMLInputElement>) {
event.preventDefault()
const address = event.target.value
this.setState({
address: address
})
}
render() {
return (
<div>
{console.log('log in the render method')}
{console.log(this.state)}
vote smart kids
need to connect the redux and suff to make request
<input
type='text'
placeholder='Address'
onChange={ e => this.handleAddress(e) }
/>
<button
onClick={ e => this.lookupAddress(e) }
>
Submit for info
</button>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
address: '',
userAddressData: {}
}
}
const mapDispatchToProps = (dispatch) => {
return {
fetchAddressData: (url) => dispatch(getAddressData(url))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(VoteSmartLocallyComponent)
我可以调用 this.props.fetchAddressData(fullRepURL)
调用我的操作
//voteSmartActions.tsx
import {Action} from 'redux'
import store from '../store/store'
import axios from 'axios'
interface VoteSmartAction<Action> {
type: string
payload?: any
}
const getAddressData = (fullURL: string) => {
return function(dispatch, getState) {
if (fullURL !== '') {
return axios.get(fullURL).then(function (response) {
dispatch(addressDataSuccess(response))
}).catch(function (error) {
console.log(error)
})
}
}
}
const addressDataSuccess = (addressData: any) => {
return {
type: 'HANDLE_RETURN_DATA',
payload: addressData,
addressData
}
}
export {
getAddressData, VoteSmartAction
}
然后从那里转到我的减速器
//voteSmartReducer.tsx
import {Action} from 'redux'
import {VoteSmartAction, getAddressData} from '../actions/voteSmartActions'
import axios from 'axios'
const INITIAL_STATE: any = {
address: '',
userAddressData: {}
}
const VoteSmartReducer = (state: any = INITIAL_STATE, action: VoteSmartAction<Action>): any => {
switch(action.type) {
case "HANDLE_RETURN_DATA":
console.log("in reducer handling return payload is")
const returnData = {
...state,
userAddressData: action.payload
}
console.log(returnData)
return returnData
default:
return state
}
}
export default VoteSmartReducer
从那里,我在减速器中创建的状态应该与我获取的数据一起返回到组件,但事实并非如此。如果有任何建议或帮助,我将不胜感激。
目前您在 mapStateToProps 中为 userAddressData
传递一个空对象,为 address
传递一个空字符串。因此您的组件将始终具有这些值。
您需要在 mapStateToProps 中指定,其中数据位于状态树中。
查看减速器的形状,查看数据在状态树中的位置,然后在 mapStateToProps 中按以下方式映射它。
例子
index.js
import { combineReducers } from 'redux'
import voteSmartReducer from './VoteSmartReducer' // assuming this is in same directory
import someOtherReducer from './someOtherReducer' // example purposes
export default combineReducers({
userAddressData: voteSmartReducer,
otherExample: someOtherReducer
})
可以看到,voteSmartReducer返回的数据映射到了combineReducers中的key userAddressData。所以 state.userAddressData
指向这个。这就是将状态映射到道具的方式。
const mapStateToProps = (state) => {
return {
userAddressData: state.userAddressData,
otherExample: state.otherExample
}
}
创建商店时,从 index.js 导入减速器并将其作为第一个参数传递给 createStore
。
示例。
import { createStore } from 'redux'
import reducers from './index.js'
const store = createStore(
reducers
)
我一直在尝试向第三方 API 提出一个简单的 URL 请求。这是我正在处理的项目(https://github.com/JMStudiosJoe/ReactPractice/tree/JMStudiosReact). I have been watching Dan Abramov videos, followed this example from redux docs and this example 并且似乎遗漏了一些小东西,因为日志显示我从 API 收到的数据已被接收并发送到减速器,但由于某种原因状态没有被发送回组件。 以下是代码摘要:
//app.tsx: 从react-redux获取store并使用Provider
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import store from './redux/store/store'
import { Provider } from 'react-redux'
import { getAddressData } from './redux/actions/voteSmartActions'
import {UIRouter, UIView, UISref, UISrefActive, pushStateLocationPlugin} from 'ui-router-react';
import NavigationBarComponent from './components/navigationBarComponent'
store.dispatch(getAddressData(''))
ReactDOM.render(
<Provider store={store}>
<NavigationBarComponent userType='buyer' />
</Provider>,
document.getElementById("root")
);
有问题的组件从 projectsComponent.tsx 文件中加载
if(projectName == 'Vote Smart Locally' ) {
return (
<VoteSmartLocallyComponent />
)
}
//voteSmartLocallyComponent.tsx
import * as React from 'react'
import { connect } from 'react-redux'
import { getAddressData } from '../../redux/actions/voteSmartActions'
import store from "../../redux/store/store"
interface VoteSmartState {
address: string
userAddressData?: any
}
interface VoteSmartProps {
fetchAddressData: any
}
const API_KEY = 'AIzaSyCWhwRupMs7IeE4IrGEgHtT0Nt-IGZnP9E'
const endURL = '&key='+ API_KEY
const baseRepURL = 'https://www.googleapis.com/civicinfo/v2/representatives?address='
const baseElectionsURL = 'https://www.googleapis.com/civicinfo/v2/elections?alt=json&prettyPrint=true'
class VoteSmartLocallyComponent extends React.Component<VoteSmartProps, VoteSmartState> {
constructor(props) {
super(props)
console.log(props)
this.state = {
address: '',
userAddressData: {}
}
}
removeSpacesAddPluses() {
return this.state.address.split(' ').join('+')
}
lookupAddress(event: React.MouseEvent<HTMLButtonElement>) {
event.preventDefault()
const address = this.removeSpacesAddPluses()
const fullRepURL = baseRepURL + address + endURL
const fullElectionsURL = baseElectionsURL + address + endURL
this.props.fetchAddressData(fullRepURL)
/*
store.subscribe(this.render)
store.dispatch({
type: 'LOOKUP_ADDRESS',
payload: address
})
*/
}
handleAddress(event: React.ChangeEvent<HTMLInputElement>) {
event.preventDefault()
const address = event.target.value
this.setState({
address: address
})
}
render() {
return (
<div>
{console.log('log in the render method')}
{console.log(this.state)}
vote smart kids
need to connect the redux and suff to make request
<input
type='text'
placeholder='Address'
onChange={ e => this.handleAddress(e) }
/>
<button
onClick={ e => this.lookupAddress(e) }
>
Submit for info
</button>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
address: '',
userAddressData: {}
}
}
const mapDispatchToProps = (dispatch) => {
return {
fetchAddressData: (url) => dispatch(getAddressData(url))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(VoteSmartLocallyComponent)
我可以调用 this.props.fetchAddressData(fullRepURL)
调用我的操作
//voteSmartActions.tsx
import {Action} from 'redux'
import store from '../store/store'
import axios from 'axios'
interface VoteSmartAction<Action> {
type: string
payload?: any
}
const getAddressData = (fullURL: string) => {
return function(dispatch, getState) {
if (fullURL !== '') {
return axios.get(fullURL).then(function (response) {
dispatch(addressDataSuccess(response))
}).catch(function (error) {
console.log(error)
})
}
}
}
const addressDataSuccess = (addressData: any) => {
return {
type: 'HANDLE_RETURN_DATA',
payload: addressData,
addressData
}
}
export {
getAddressData, VoteSmartAction
}
然后从那里转到我的减速器
//voteSmartReducer.tsx
import {Action} from 'redux'
import {VoteSmartAction, getAddressData} from '../actions/voteSmartActions'
import axios from 'axios'
const INITIAL_STATE: any = {
address: '',
userAddressData: {}
}
const VoteSmartReducer = (state: any = INITIAL_STATE, action: VoteSmartAction<Action>): any => {
switch(action.type) {
case "HANDLE_RETURN_DATA":
console.log("in reducer handling return payload is")
const returnData = {
...state,
userAddressData: action.payload
}
console.log(returnData)
return returnData
default:
return state
}
}
export default VoteSmartReducer
从那里,我在减速器中创建的状态应该与我获取的数据一起返回到组件,但事实并非如此。如果有任何建议或帮助,我将不胜感激。
目前您在 mapStateToProps 中为 userAddressData
传递一个空对象,为 address
传递一个空字符串。因此您的组件将始终具有这些值。
您需要在 mapStateToProps 中指定,其中数据位于状态树中。
查看减速器的形状,查看数据在状态树中的位置,然后在 mapStateToProps 中按以下方式映射它。
例子
index.js
import { combineReducers } from 'redux'
import voteSmartReducer from './VoteSmartReducer' // assuming this is in same directory
import someOtherReducer from './someOtherReducer' // example purposes
export default combineReducers({
userAddressData: voteSmartReducer,
otherExample: someOtherReducer
})
可以看到,voteSmartReducer返回的数据映射到了combineReducers中的key userAddressData。所以 state.userAddressData
指向这个。这就是将状态映射到道具的方式。
const mapStateToProps = (state) => {
return {
userAddressData: state.userAddressData,
otherExample: state.otherExample
}
}
创建商店时,从 index.js 导入减速器并将其作为第一个参数传递给 createStore
。
示例。
import { createStore } from 'redux'
import reducers from './index.js'
const store = createStore(
reducers
)