2017-08-28 24 views
0

我在下面的頁面陣營:凡持有狀態,一個回調後一直存在,直到一些運行

@connect((store) => { 
    return { 
    all_orders_data: store.trends.all_orders_data, 
    ...etc... 
    }; 
}) 
class OrdersController extends MyComponent { 

    constructor(props){ 
     let custom_methods = ['refreshData', 'runDispatch']; 
     super(props, custom_methods); 
     this.state = {last_updated_at: new Date()}; 
    } 

    componentWillMount() { 
     this.runDispatch(); 
     // this.props.dispatch(fetchOrderData()); 
    } 

    componentDidMount() { 
     this.refreshTimerID = setInterval(
      () => this.refreshData(), 
      300 * 1000 // 5 minutes 
     ); 
    } 

    refreshData() { 
     console.log('running refresh'); 
     this.runDispatch(true); 
     this.setState({last_updated_at: new Date()}); 

    } 

    runDispatch(refresh=false) { 
     this.props.dispatch(fetchOrderTrendingAllOrdersData(refresh)); 
    } 

    render() { 
     return (
      <div> 
       <h1>Order Trending</h1> 
       {last_updated_at} 
       <br/> 
       <div className="card col-md-12"> 
        <h2 className="style-1">All Orders</h2> 
        <LineChart 
         data={all_orders_data} 
         fetched={fetched_all_orders_data} 
         error={error_in_fetching_all_orders_data} 
        /> 
       </div> 
      </div> 
     ) 
    } 

在渲染我解開道具,last_updated頭,並呈現一個折線圖。

enter image description here

我希望能夠點擊的按鈕切換圖表上線。要做到這一點,我必須跟蹤data變量的密鑰以顯示爲行。

我不能把這些行選項放在構造函數中,因爲runDispatch直到componentWillMount才被觸發。

我不能把它放在componentWillMount中,因爲我不知道runDispatch何時會返回數據直到它返回。

我可以在reducer中獲得all_orders_data的密鑰並將其作爲道具傳遞給OrdersController,但道具無法更改,我希望我們的應用的此頁控制當前顯示的行。

我不想把它放在圖表組件上,因爲它每次刷新運行都會得到新的道具,我不知道它是否會在刷新後保持正確的狀態。

切換設置不需要稍後保留,只有當控制器處於活動狀態(如果他們選擇新的鏈接,我不在乎它是否重置)。

我的直覺是把狀態放在折線圖上,因爲它不必是永久的。

哪裏是正確的位置,以保持這些線路鍵的狀態,如:

{ 
    all_orders: ['Online orders', 'Web orders', ...] 
} 

讓用戶切換,他希望看到的圖表是什麼線?它可以在LineChart,控制器,一個新的redux道具等。

回答

0

我決定把它放在LineChart本身,因爲它的按鈕切換線。它沒有工作,但你可以在componentWillReceiveProps保護狀態:

import React from 'react'; 
import ReactLoading from 'react-loading'; 
import { 
    VictoryChart, 
    VictoryLine, 
    VictoryTheme, 
    VictoryAxis, 
    VictoryTooltip, 
    VictoryBar, 
    VictoryVoronoiContainer 
} from 'victory'; 
import _ from 'underscore'; 

import MyComponent from '../main/MyComponent'; 


const COLOR_OPTIONS = [ 
    '#c43a31', // dark red 
    'blue', 
    'green', 
    'yellow', 
    'purple', 
    'teal', 
    'orange' 
]; 

function getTimestringFromUnixTimestamp(timestamp) { 
    // just default it to AM for now 
    let period = 'AM' 
    let date = new Date(timestamp); 
    let hours = date.getHours(); 
    let minutes = date.getMinutes(); 

    if (hours >= 12) { 
     period = 'PM'; 
    } 

    if (hours == 0) { 
     hours += 12; 
    } else if (hours >= 13) { 
     hours -= 12; 
    } 

    hours = "0" + hours; 
    minutes = "0" + minutes; 
    // Will display time in 10:30 AM format 
    let formattedTime = `${hours.substr(-2)}:${minutes.substr(-2)} ${period}`; 
    return formattedTime 
} 

function displayTooltips(data) { 
    // x is the unix timestamp, y is the order count 
    let { x, y } = data; 
    let formattedTime = getTimestringFromUnixTimestamp(x); 
    // https://stackoverflow.com/questions/847185/convert-a-unix-timestamp-to-time-in-javascript 
    return `Time - ${formattedTime}\nOrder Count - ${y}` 
} 




export default class LineChart extends MyComponent { 

    constructor(props) { 
     let custom_methods = [ 
      'generateVictoryLines', 
      'generateToggleButtons', 
      'toggleItemOnclick', 
      'toggleAllLines', 
     ]; 
     super(props, custom_methods); 

     this.state = { 
      active_line_keys: [], 
      available_line_keys: [] 
     }; 
    } 

    componentWillReceiveProps(nextProps) { 
     console.log('\n\ncomponentWillReceiveProps:'); 
     let data = nextProps.data; 
     console.log(data); 
     if (data) { 
      let line_keys = Object.keys(data); 
      console.log('line_keys:'); 
      console.log(line_keys); 
      console.log('this.state.available_line_keys:'); 
      console.log(this.state.available_line_keys); 
      let is_equal = _.isEqual(_.sortBy(line_keys), _.sortBy(this.state.available_line_keys)); 
      if (!is_equal) { 
       console.log('line keys are diff; need to update state'); 
       this.setState({ 
        available_line_keys: line_keys, 
        active_line_keys: line_keys 
       }); 
      } 
     } 
    } 

    generateVictoryLines() { 
     return this.state.active_line_keys.map((key, index) => { 
      let this_keys_permanent_index = this.state.available_line_keys.indexOf(key); 
      let color = COLOR_OPTIONS[this_keys_permanent_index]; 
      return (
       <VictoryLine 
        labels={displayTooltips} 
        labelComponent={<VictoryTooltip/>} 
        style={{ 
        data: { stroke: `${color}` }, 
        parent: { border: `1px solid #ccc`} 
        }} 
        data={this.props.data[key]} 
       /> 
      ) 
     }); 
    } 

    generateToggleButtons() { 
     return this.state.available_line_keys.map((key, index) => { 
      let this_keys_permanent_index = this.state.available_line_keys.indexOf(key); 
      let color = COLOR_OPTIONS[this_keys_permanent_index]; 
      console.log(key); 
      return (
       <button onClick={this.toggleItemOnclick.bind(null, key)} style={ {color: color}}>{key}</button> 
      ); 
     }) 
    } 

    toggleItemOnclick(name) { 
     console.log('\ntoggleItemOnclick:'); 
     console.log(name); 
     console.log(this.state); 
     let is_in_active_line_keys = this.state.active_line_keys.indexOf(name) != -1; 
     console.log(is_in_active_line_keys); 

     let new_active_line_keys; 
     if (is_in_active_line_keys) { 
      new_active_line_keys = this.state.active_line_keys.filter(e => e !== name); // e is each item in the list; filter 
      // this.setState({active_line_keys: new_active_line_keys}); 
     } else { 
      new_active_line_keys = this.state.active_line_keys.slice(); 
      new_active_line_keys.push(name); 
     } 

     console.log(new_active_line_keys); 

     this.setState({active_line_keys: new_active_line_keys}); 
     // arr = arr.filter(e => e !== el); 
    } 

    toggleAllLines() { 
     if (this.state.active_line_keys.length < this.state.available_line_keys.length) { 
      this.setState({active_line_keys: this.state.available_line_keys}); 
     } else { 
      this.setState({active_line_keys: []}); 
     } 
    } 

    // addAllLines() { 
    //  this.setState({active_line_keys: this.state.available_line_keys}); 
    // } 

    render() { 
     let graph_body; 
     let { data, error, fetched } = this.props; // we don't need data here 
     let victory_lines = this.generateVictoryLines(); 
     let buttons = this.generateToggleButtons(); 

     if (error) { 
      // alert(error); 
      console.log('\n\nerror:'); 
      console.log(error); 
      graph_body = (<h2 className="centered">Error retrieving data</h2>); 
     } else if (fetched == false) { 
      graph_body = (
       <div className="card col-md-12"> 
        <span><h2 style={{fontWeight: "bold", fontSize: "25px", color: "#F96302"}}>Just a moment...Your request is being processed.</h2> 
        <ReactLoading type="cylon" color="#F96302" /></span> 
       </div> 
      ) 
     } else { 
      try { 

       // in the victoryLine, interpolation="natural" will smooth graph out 

       graph_body = (
        <div> 
         <VictoryChart 
         theme={VictoryTheme.material} 
         scale={{x: "time", y: "linear"}} 
         animate={{duration: 650}} 
         containerComponent={<VictoryVoronoiContainer/>} 
         width={1500} 
         height={600} 
         > 
          <VictoryAxis style={ { tickLabels: {fontSize: '20px'} } }/> 
          <VictoryAxis 
          dependentAxis 
          tickValues={[20, 40, 60, 80, 100]} 
          style={ { tickLabels: {fontSize: '20px'} } } 
          /> 
          {victory_lines} 

         </VictoryChart> 
         <button onClick={this.toggleAllLines}>Toggle lines</button> 
         {buttons} 

        </div> 
       ) 
      } catch(err) { 
       graph_body = (<h2 className="centered">Error using response: {`${err}`}</h2>); 
      } 
     } 

     return (
      <div> 
       {graph_body} 
      </div> 
     ) 
    } 

} 
相關問題