我在react(下图)中有一个布局组件。通过this.props.children(或者现在的childrenWithProps)注入到这个组件中的两个组件都有一个我为它们创建的日期范围组件,允许用户选择从api中提取的数据范围。一个是球员仪表板,一个是球队仪表板(默认视图,在第二个代码块中显示)。当用户在球队仪表板上搜索球员并移动到球员仪表板时,我希望所选择的日期范围(存储为this.state.startDate和this.state.EndDate)可以转移到球员仪表板中,反之亦然。我觉得这是redux的一个很好的用例,但到目前为止,我只能通过传递props来实现,而日期范围的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>
);
}
}
这是Team Dashboard
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>
);
}
}
看看你的代码,我想说没有redux的最佳选择是将日期范围状态移动到封装两个仪表板的父组件中,例如CoreLayout,并将范围作为道具传递下去。
切换到Redux是值得考虑的,虽然它一开始看起来令人生畏,但在你尝试之后它真的非常简单,确实使生活更容易。