2017-02-03 117 views
1

我試圖設置一個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." 
+1

它使你的數據庫無限通話,因爲你調用'componentDidUpdate'的API,然後從API的響應,這會導致'componentDidUpdate'鉤再次觸發重新設置狀態。 –

回答

2

我沒有看到任何Redux都可以在你的代碼中使用。如果您計劃使用Redux,則應將所有API邏輯移動到動作創建者處,並將API響應存儲在Redux Store中。我知道你現在正在快速建立原型。 :)

您的無限循環是由於您選擇了錯誤的生命週期方法而引起的。如果使用componentDidUpdatesetState,它將再次導致componentDidUpdate方法被調用等等。無論何時更新組件,您基本上都會進行更新,如果這是有道理的。 :D

在發送API調用之前,您可以隨時檢查新的props.params與以前有沒有(導致API調用)的不同。您會收到舊的道具並聲明該功能的參數。

https://facebook.github.io/react/docs/react-component.html#componentdidupdate

但是,如果你已經決定使用終極版,我想可能是邏輯移動到行動的創建者,存儲在你的終極版商店這種反應,只是使用這些數據在connect

+0

我正在使用Redux,因此頁面左側的組件可以與右側的組件共享數據。我試圖獲得正確組件的狀態來更新和更改URL,而左側組件保持不變。 –

+0

正如我所說,如果你想使用componentDidUpdate,你需要檢查你是否真的需要再次執行API調用。否則,你正在循環。如果你正確使用Redux,你不會有'setState'調用你,你不會面臨這個問題。另外,我沒有在你的例子中看到「左」組件,所以我不能進一步幫助你。 – CharlieBrown

+0

你說得對,我不需要在那裏執行API調用。我將它移出到另一個組件中,並且它工作正常。我在下面的評論中解決了這兩個組件,但我仍然不確定是否最好使用Redux實踐。 –

0

嘗試使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再次更新組件,使你陷入無限循環。

+0

我試過componentDidUpdate(),但它導致無限的GET請求相同的問題 –

+0

@crashspringfield你的意思是'componentDidMount'? 'componentDidUpdate'似乎是無限請求的錯誤。 –

+0

對不起,我感到困惑。 componentDidMount呈現一次。問題是我有一個左側和右側組件,我希望左側組件控制右側組件的狀態。如果我使用componentDidMount,它會呈現一次,但不會響應左側組件的更改。 –

0

我不能幫助的第一個問題,因爲我不知道這個APIManager的論據應該是什麼。

第二個問題是您在「componentDidUpdate()」中執行API請求的結果。這基本上是發生了什麼:

  1. REDX中的某些狀態更改。
  2. 遠足收到新的道具(或其狀態變化)。
  3. 遠足根據新的道具呈現。
  4. Hike現在已更新並調用您的「componentDidUpdate」函數。
  5. componentDidUpdate進行API調用,當響應返回時,它觸發setState()。
  6. 遠足的內部狀態改變時,觸發該組件的更新(!) - >轉到步驟2

當你點擊一個鏈接到另一個頁面上,無限循環繼續,後最後一次由Hike更新觸發的API調用已解決,您再次調用「setState」,它現在嘗試更新一個不能裝配更長的組件的狀態,因此發出警告。

The docs解釋這個真的很好我發現,我會給那些徹底的閱讀。

0

還在搞清楚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)), 
    } 
} 
3

看你的代碼,我想我會的建築師也略有不同

幾件事情:

  1. 嘗試移動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像任何其他行動的創建者。

  1. 既然你有一條路徑/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) 
    } 
} 
相關問題