使用API调用更新React-Redux中的组件状态
我试图设置一个React应用程序,其中单击某个组件中的地图标记时,将使用数据库中的数据重新呈现页面上的另一个组件并更改URL。它工作,有点,但不好。 我无法弄清楚从Redux获取状态并从API获取响应是否适合React生命周期。使用API调用更新React-Redux中的组件状态
有两个相关的问题:
优先:注释掉的行“//APIManager.get()......”不工作,但就行了黑客攻击,一起版本在它下面。
SECOND:我在console.log()中的行 - 无限的响应日志,并向我的数据库发出无限的GET请求。
这里是我下面的成分:
class Hike extends Component {
constructor() {
super()
this.state = {
currentHike: {
id: '',
name: '',
review: {},
}
}
}
componentDidUpdate() {
const params = this.props.params
const hack = "/api/hike/" + params
// APIManager.get('/api/hike/', params, (err, response) => { // doesn't work
APIManager.get(hack, null, (err, response) => { // works
if (err) {
console.error(err)
return
}
console.log(JSON.stringify(response.result)) // SECOND
this.setState({
currentHike: response.result
})
})
}
render() {
// Allow for fields to be blank
const name = (this.state.currentHike.name == null) ? null : this.state.currentHike.name
return (
<div>
<p>testing hike component</p>
<p>{this.state.currentHike.name}</p>
</div>
)
}
}
const stateToProps = (state) => {
return {
params: state.hike.selectedHike
}
}
export default connect(stateToProps)(Hike)
另外:当我点击页面上的链接转到另一个URL,我得到以下错误:
"Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op."
我没有看到任何Redux都可以在你的代码中使用。如果您计划使用Redux,则应将所有API逻辑移动到动作创建者处,并将API响应存储在Redux Store中。我知道你现在正在快速建立原型。 :)
您的无限循环是由于您选择了错误的生命周期方法而引起的。如果使用componentDidUpdate
和setState
,它将再次导致componentDidUpdate
方法被调用等等。无论何时更新组件,您基本上都会进行更新,如果这是有道理的。 :D
在发送API调用之前,您可以随时检查新的props.params
与以前有没有(导致API调用)的不同。您会收到旧的道具并声明该功能的参数。
https://facebook.github.io/react/docs/react-component.html#componentdidupdate
但是,如果你已经决定使用终极版,我想可能是逻辑移动到行动的创建者,存储在你的终极版商店这种反应,只是使用这些数据在connect
。
我正在使用Redux,因此页面左侧的组件可以与右侧的组件共享数据。我试图获得正确组件的状态来更新和更改URL,而左侧组件保持不变。 –
正如我所说,如果你想使用componentDidUpdate,你需要检查你是否真的需要再次执行API调用。否则,你正在循环。如果你正确使用Redux,你不会有'setState'调用你,你不会面临这个问题。另外,我没有在你的例子中看到“左”组件,所以我不能进一步帮助你。 – CharlieBrown
你说得对,我不需要在那里执行API调用。我将它移出到另一个组件中,并且它工作正常。我在下面的评论中解决了这两个组件,但我仍然不确定是否最好使用Redux实践。 –
尝试使API调用componentDidMount
:
componentDidMount() {
// make your API call and then call .setState
}
做那,而不是的componentDidUpdate
内。
有很多方法可以在您的React应用程序内构建您的API调用。例如,看看这篇文章:React AJAX Best Practices。如果该链接被打破,它概述了一些想法:
Root Component
This is the simplest approach so it's great for prototypes and small apps.
With this approach, you build a single root/parent component that issues all your AJAX requests. The root component stores the AJAX response data in it's state, and passes that state (or a portion of it) down to child components as props.
由于这是外部的问题的范围,我将离开你到了一些研究,但对管理国家的一些其他方法和异步API调用涉及像Redux这样的库,它现在是React的事实上的状态管理器之一。
顺便说一下,你的无限调用来自于这样一个事实,即当你的组件更新时,它会进行一次API调用,然后调用setState
再次更新组件,使你陷入无限循环。
我试过componentDidUpdate(),但它导致无限的GET请求相同的问题 –
@crashspringfield你的意思是'componentDidMount'? 'componentDidUpdate'似乎是无限请求的错误。 –
对不起,我感到困惑。 componentDidMount呈现一次。问题是我有一个左侧和右侧组件,我希望左侧组件控制右侧组件的状态。如果我使用componentDidMount,它会呈现一次,但不会响应左侧组件的更改。 –
我不能帮助的第一个问题,因为我不知道这个APIManager的论据应该是什么。
第二个问题是您在“componentDidUpdate()”中执行API请求的结果。这基本上是发生了什么:
- REDX中的某些状态更改。
- 远足收到新的道具(或其状态变化)。
- 远足根据新的道具呈现。
- Hike现在已更新并调用您的“componentDidUpdate”函数。
- componentDidUpdate进行API调用,当响应返回时,它触发setState()。
- 远足的内部状态改变时,触发该组件的更新(!) - >转到步骤2
当你点击一个链接到另一个页面上,无限循环继续,后最后一次由Hike更新触发的API调用已解决,您再次调用“setState”,它现在尝试更新一个不能装配更长的组件的状态,因此发出警告。
The docs解释这个真的很好我发现,我会给那些彻底的阅读。
还在搞清楚Redux的流程,因为它解决了将API请求从Hike组件移动到正在监听的组件时的问题。 现在,只要数据库信息赶上重新路由和重新呈现,Hike组件就会监听并重新呈现。
Hike.js
class Hike extends Component {
constructor() {
super()
this.state = {}
}
componentDidUpdate() {
console.log('dealing with ' + JSON.stringify(this.props.currentHike))
}
render() {
if (this.props.currentHike == null || undefined) { return false }
const currentHike = this.props.currentHike
return (
<div className="sidebar">
<p>{currentHike.name}</p>
</div>
)
}
}
const stateToProps = (state) => {
return {
currentHike: state.hike.currentHike,
}
}
和“this.props.currentHikeReceived()”得到搬回行动做在其他设备一切,让我不再担心翘尾因素组件重新无限呈现自己。
Map.js
onMarkerClick(id) {
const hikeId = id
// Set params to be fetched
this.props.hikeSelected(hikeId)
// GET hike data from database
const hack = "/api/hike/" + hikeId
APIManager.get(hack, null, (err, response) => {
if (err) {
console.error(err)
return
}
this.props.currentHikeReceived(response.result)
})
// Change path to clicked hike
const path = `/hike/${hikeId}`
browserHistory.push(path)
}
const stateToProps = (state) => {
return {
hikes: state.hike.list,
location: state.newHike
}
}
const dispatchToProps = (dispatch) => {
return {
currentHikeReceived: (hike) => dispatch(actions.currentHikeReceived(hike)),
hikesReceived: (hikes) => dispatch(actions.hikesReceived(hikes)),
hikeSelected: (hike) => dispatch(actions.hikeSelected(hike)),
locationAdded: (location) => dispatch(actions.locationAdded(location)),
}
}
看你的代码,我想我会的建筑师也略有不同
几件事情:
- 尝试移动API调用和获取数据到Redux行动。由于API获取是异步的,我认为这是最好使用Redux Thunk
例如:
function fetchHikeById(hikeId) {
return dispatch => {
// optional: dispatch an action here to change redux state to loading
dispatch(action.loadingStarted())
const hack = "/api/hike/" + hikeId
APIManager.get(hack, null, (err, response) => {
if (err) {
console.error(err);
// if you want user to know an error happened.
// you can optionally dispatch action to store
// the error in the redux state.
dispatch(action.fetchError(err));
return;
}
dispatch(action.currentHikeReceived(response.result))
});
}
}
可以映射派遣道具fetchHikeById此外,通过治疗fetchHikeById像任何其他行动的创建者。
- 既然你有一条路径
/hike/:hikeId
我假设你也在更新路线。所以如果你想让人们预订标记并保存并且url.../hike/2
或者回到它。您仍然可以将提取放入Hike组件中。
你把fetchHikeById动作的生命周期方法是。
componentDidMount() {
// assume you are using react router to pass the hikeId
// from the url '/hike/:hikeId'
const hikeId = this.props.params.hikeId;
this.props.fetchHikeById(hikeId);
}
componentWillReceiveProps(nextProps) {
// so this is when the props changed.
// so if the hikeId change, you'd have to re-fetch.
if (this.props.params.hikeId !== nextProps.params.hikeId) {
this.props.fetchHikeById(nextProps.params.hikeId)
}
}
它使你的数据库无限通话,因为你调用'componentDidUpdate'的API,然后从API的响应,这会导致'componentDidUpdate'钩再次触发重新设置状态。 –