React.js处理不是父/子

时间:2016-06-29 17:12:09

标签: javascript reactjs redux react-redux

我有一个布局组件(下面)。我通过this.props.children(或现在的childrenWithProps)注入此组件的两个组件有一个我为它们创建的日期范围组件,允许用户选择从teh api中提取的数据范围。一个是播放器仪表板,一个是团队仪表板(默认视图,显示在第二个代码块中)。当用户在团队仪表板上并搜索播放器并移动到该播放器仪表板时,我希望选择的日期范围(存储为this.state.startDate和this.state.EndDate)继续进入播放器仪表板,然后反之亦然。我觉得这是redux的一个很好的用例,但到目前为止,我已经设法通过传递道具和日期范围的redux实现似乎令人生畏。任何帮助将非常感激。此外,我有新的反应,知道我需要做大量的重新格式化。

import React, { PropTypes, Component } from 'react';
import '../../styles/core.scss';
import TopNav from 'components/top-nav';
import LeftNav from 'components/left-nav';

export default class CoreLayout extends Component {
  static propTypes = {
    children: PropTypes.element
 };

constructor(props, context) {
    super(props, context);
    this.state = {
        team: null,
        teamPositions: []
    };
}

activeTeam(team){
    console.log(team);
    this.setState({
        team: team
    }, () => {
        return this.state;
    });
}

componentWillMount() {
}

getTeamPositions(positions){
    this.setState({
        teamPositions: positions
    }, () => {
        return this.state;
    });
}

render() {
    var childrenWithProps = React.Children.map(this.props.children, (child) => React.cloneElement(child, { team: this.state.team, teamPositions: this.state.teamPositions }));
    return (
      <div className='page-container'>
          <TopNav
            onTeamChange={team => this.activeTeam(team)}
            sendTeamPositions={positions => this.getTeamPositions(positions)}
            />
          <LeftNav />
          {( this.state.team !== null ) ?
        <div className='view-container'>
          { childrenWithProps }
        </div>
        : null }
      </div>
    );
  }
}

这是团队仪表板

import React, { PropTypes, Component } from 'react';
import { getDataRange, getTeams, getFile, getAllHitsData, getPlayers} from 'api/index.js';
import moment from 'moment';
import {Table, Thead, Th, Tr, Td} from 'components/Reactable';
import Autosuggest from 'react-autosuggest';
import { Link } from 'react-router';
import ScatterPlot from 'components/scatterplot';
import DashboardStats from 'components/dashboard-stats';
import DateRangeComponent from 'components/date-range';
import AdminSquare from 'components/admin-square';

let allHitDatas = [];
let hitDatas = [];
let teams = [];
let newFile = '';
let players = [];

export default class Dashboard extends Component {
  static propTypes = {
   team: PropTypes.object.isRequired
  //  teamPositions: PropTypes.array.isRequired
};
constructor(props, context) {
    super(props, context);
    this.state = {
        showRangePicker: false,
        hitDatas: [],
        teams: [],
        start: '',
        end: '',
        team: this.props.team,
        selectedTeamID: null,
        selectedTeamName: "",
        newFileConfirmation: false,
        players: [],
        allHitDatas: [],
        suggestions: this.getSuggestions(''),
        startDate: moment().format('YYYY-MM-DD'),
        endDate: moment().format('YYYY-MM-DD'),
        selected: '',
        showDatePickerControls: false,
        showScatterPlot: true
    };
    this.onChange = this.onChange.bind(this);
    this.onSuggestionsUpdateRequested = this.onSuggestionsUpdateRequested.bind(this);
}

onChange(event, { newValue }) {
    this.setState({
        value: newValue
    });
}

onSuggestionsUpdateRequested({ value }) {
    this.setState({
        suggestions: this.getSuggestions(value)
    });
}

  formatDate(date) {
    return moment(date).format('YYYY-MM-DD');
  }

  formatDisplayDate(date) {
    return moment(date).format('MMMM DD, YYYY');
  }

  componentWillReceiveProps() {
      this.setState({
         team: this.props.team,
         selectedTeamID: this.props.team.id
     }, () => {
         this.dataChangeHelper();
     });
      console.log(this.props);
  }

  componentWillMount() {
    console.log(this.props);
    let defaultStartDate = "03/01/15";
    let defaultEndDate = "05/18/16";
    const config = {
        start: this.state.startDate || defaultStartDate,
        end: this.state.endDate || defaultEndDate,
        team: this.props.team.id
    };

    getAllHitsData(config)
    .then((response) => {
      allHitDatas = response.data;
      this.setState({
        allHitDatas: allHitDatas
      }, () => {
          return this.state;
      });
    });

    getDataRange(config)
        .then((response) => {
            hitDatas = response.data;
            this.setState({
                hitDatas: hitDatas,
                start: config.start,
                end: config.end
            });
        });
    getTeams().then((response) => {
        teams = response.data;
        this.setState({teams: teams});
    });

    getPlayers().then((response) => {
        players = response.data;
        this.setState({
            players: players
        }, () => {
                return this.state;
        });
    });
}

getSuggestions(value) {
    const inputValue = value.trim().toLowerCase();
    const inputLength = inputValue.length;
    return inputLength === 0 ? [] : players.filter(player =>
        (player.NameFirst.toLowerCase().slice(0, inputLength) === inputValue || player.NameLast.toLowerCase().slice(0, inputLength) === inputValue)
    );
}

getSuggestionValue(suggestion) { // when suggestion selected, this function tells
  return suggestion.NameFirst;   // what should be the value of the input
}

renderSuggestion(suggestion) {
  return (
    <span><Link to={ "/view-player/" + suggestion.id }>{ suggestion.NameFirst + " " + suggestion.NameLast }</Link></span>
  );
}

shouldRenderSuggestions(value) {
      if (value) {
          return value.trim().length > 0;
      }
}

renderReactable(hitDatas) {
    return hitDatas.map((hitData) => {
        // console.log(hitData);
        if (Number(hitData.playerTeamId) === Number(this.state.selectedTeamID) || this.state.selectedTeamID === null) {
            return (
                <Tr key={hitData.MaxHic}>
                    <Td column="name" data={hitData.playerNameLast + ', ' + hitData.playerNameFirst} />
                    <Td column="numHits" data={hitData.numHits} />
                    <Td column="maxHic" data={Math.round(hitData.MaxHic)} />
                </Tr>
            );
        }
    });
}

renderReactableTwo(allHitDatas) {
    return allHitDatas.map((hitData) => {
        // console.log(hitData);
        if (Number(hitData.playerTeamId) === Number(this.state.selectedTeamID) || this.state.selectedTeamID === null) {
            return (
                <Tr key={hitData.Hic}>
                    <Td column="name" data={hitData.playerNameLast + ', ' + hitData.playerNameFirst} />
                    <Td column="hic" data={Math.round(hitData.Hic)} />
                </Tr>
            );
        }
    });
}

dataChangeHelper() {
  console.log(this.props);
    const newConfig = {
      start: this.state.startDate,
      end: this.state.endDate,
      team: this.props.team.id
    };

    getDataRange(newConfig)
    .then((response) => {
      hitDatas = response.data;
      this.setState({
        hitDatas: hitDatas
      });
    });
    getAllHitsData(newConfig)
    .then((response) => {
      console.log(response);
      allHitDatas = response.data;
      this.setState({
        allHitDatas: allHitDatas
      });
    });

}

showNewDateRange(newStartDate, newEndDate) {
  this.setState({
    startDate: newStartDate,
    endDate: newEndDate
    // showDatePickerControls:false
  }, () => {
    this.dataChangeHelper();
 });
}

handleImpactClick(d) {
 console.log(d);
}

render () {
  if (this.state.teams.length === 0 || this.state.players.length === 0) {
    return (
        <div className="no-data-container">
            <div className="no-data-message">We don't have any data for you right now. Would you like
                to add some players, teams, or devices?
            </div>
            <ul className="no-data-links">
                <AdminSquare title="PLAYER ADMIN" icon="person" link="/player"/>
                <AdminSquare title="TEAM ADMIN" icon="group" link="/team"/>
                <AdminSquare title="DEVICE ADMIN" icon="sd_storage" link="/device"/>
            </ul>
        </div>
    );
}

const { value, suggestions } = this.state;
const inputProps = {
  placeholder: 'Search for a player',
  value,
  onChange: this.onChange
};

return (
    <div>
        <div className='admin-table-wrapper'>
            <div className="homeview-subnav">
                <div className="view-title">Team Data</div>
                <DateRangeComponent
                    startDate={this.state.startDate}
                    endDate={this.state.endDate}
                    onDateChange={(newStartDate, newEndDate) => this.showNewDateRange(newStartDate, newEndDate)}
                />
                <Autosuggest
                    suggestions={suggestions}
                    onSuggestionsUpdateRequested={this.onSuggestionsUpdateRequested}
                    shouldRenderSuggestions={this.shouldRenderSuggestions.bind(this)}
                    getSuggestionValue={this.getSuggestionValue.bind(this)}
                    renderSuggestion={this.renderSuggestion.bind(this)}
                    inputProps={inputProps}
                />
                <button className="retrieve-file-trigger" onClick={this.retrieveFile.bind(this)}><i className='material-icons small file-icon'>file_download</i></button>
            </div>
            <div className="top-dashboard-data-container">
                <div id="home-scatter-container">
                  <ScatterPlot
                    data={this.state.allHitDatas}
                    statOneTitle='HIC'
                    location='#home-scatter-container'
                    showScatterPlot={this.state.showScatterPlot}
                    sendHitData={(d) => this.handleImpactClick(d)}
                 />
                </div>
                <DashboardStats
                    impactsRecorded={12456712}
                    devicesActive={27}
                    highestHic={234}
                />
            </div>
            <div className="table-wrapper">
            <div className="table-title">TOP HICS</div>
            <Table
                className="table table-dashboard"
                itemsPerPage={10}
                pageButtonLimit={5}
                noDataText="No data available for this filter set"
                sortable
                defaultSort={{column: 'hic', direction: 'desc'}}>
                <Thead>
                    <Th column="name">
                        <strong className="name-header">NAME</strong>
                    </Th>
                    <Th column="hic">
                        <strong className="position-header">HIC</strong>
                    </Th>
                </Thead>
                { this.renderReactableTwo(this.state.allHitDatas) }
            </Table>
            </div>
            <div className="table-wrapper">
            <div className="table-title">MOST HITS</div>
            <Table
                className="table table-dashboard"
                itemsPerPage={10}
                pageButtonLimit={5}
                noDataText="No data available for this filter set"
                sortable
                defaultSort={{column: 'maxHic', direction: 'desc'}}>
                <Thead>
                    <Th column="name">
                        <strong className="name-header">NAME</strong>
                    </Th>
                    <Th column="numHits">
                        <strong className="position-header"># OF HITS</strong>
                    </Th>
                    <Th column="maxHic">
                        <strong className="position-header">TOP HIC</strong>
                    </Th>
                </Thead>
              { this.renderReactable(this.state.hitDatas) }
            </Table>
            </div>
        </div>
      </div>
    );
  }
}

1 个答案:

答案 0 :(得分:0)

查看你的代码我会说没有redux的最佳选择是将日期范围状态移动到封装两个仪表板的父组件中,例如CoreLayout,并将范围作为props传递。

值得考虑切换到Redux,它起初看起来令人生畏,但是在你放手之后真的非常简单,确实让生活更轻松。