我正在使用React-Redux编写一个指标页面,我之前没有使用它,并且在构建它时遇到了麻烦。
基本结构是这样的:
<input id=start_date />
<input id=end_date />
<button id=submit onClick={ this.props.fetchChartData() }/>
<Chart1 />
<Chart2 />
商店结构如下:
dates
start_date: "2016-09-16"
end_date: "2016-09-16"
charts
Chart1
api_func: "get_supported_events"
fetching: false
fetched: false
data: null
error: null
Chart2
api_func: "get_events_closed"
fetching: false
fetched: false
data: null
error: null
使用thunk,我现在的行动包括以下功能:
function getStateURL(state){
return state.charts.Chart1['api_func'];
}
export function fetchChartData(){
return (dispatch, getState) => {
dispatch(fetchChartDataStart());
return fetch(getStateURL(getState()))
.then((response) => response.json())
.then((json) => dispatch(receiveChartData(json)))
.catch((err) => dispatch(fetchChartDataError(err)));
}
}
问题是,我不想对图表名称进行硬编码,因为我觉得我应该能够编写一个动作,因为所有图表都需要做同样的事情。
我能想到的最佳解决方案是让按钮触发图表组件可以监听的事件,以便在请求状态时它仅限于图表的部分,而不是整个状态。有没有办法让反应组件触发可被其他组件捕获的事件?
答案 0 :(得分:0)
当商店只是EventEmitter的一个实例时,您提出的解决方案似乎更像是旧的Flux模型。
使用Flux,您可以<Chart />
喜欢
class Chart extends Component {
componentDidMount() {
store.addEventListener('fetchData', this.fetchData);
}
componentWillUnmount() {
store.removeEventListener('fetchData', this.fetchData);
}
this.fetchData() {
api.fetchChartData(store.get('chart1.url');
}
render() {
...
}
}
然而,Redux
并不是显而易见的。但是有可能做到这一点:
class Chart1 extends Component {
componentWillReceiveProps(nextProps) {
if (!nextProps.fetching && !nextProps.fetched) {
const { fetchData, url } = this.props;
fetchData(url);
}
}
render() {
...
}
}
export default connect(state => ({
fetching: state.Chart1.fetching
fetched: state.Chart1.fetched
url: state.Chart1.url
}), {
fetchData
})(Chart1)
并在/action.js
export function fetchChartData(url){
return (dispatch) => {
dispatch(fetchChartDataStart());
return fetch(url)
.then((response) => response.json())
.then((json) => dispatch(receiveChartData(json)))
.catch((err) => dispatch(fetchChartDataError(err)));
}
}
考虑到所有<Chart />
组件中的类似功能,值得为此实现高阶组件,并将url保留为常量而不是存储。
export const fetchData = (url) => (Wrapped) => {
class Wrapper extends Component {
componentWillReceiveProps(nextProps) {
if (!nextProps.fetching && !nextProps.fetched) {
const { fetchData, url } = this.props;
fetchData(url);
}
}
render() {
return <Wrapped {...this.props} />
}
}
return connect(null, { fetchData })(Wrapper);
}
在Chart.jsx
中使用它:
import { chart1Url } from '.../someconstants';
import { fetchData } from '/hocs/fetchData'
const Chart1 = () => {
return <div>...</div>;
}
export default fetchData(chartUrl)(Chart1);
尽管有可能,我仍然认为最好的解决方案是将URL存储在常量文件中,并将api函数放在另一个模块中。你可以这样做: ./api/fetchData.js
export function fetchData(url) {
return new Promise((resolve, reject) =>
fetch(url)
.then((response) => response.json())
.then((json) => resolve(json))
.catch((err) => reject(err));
}
./ actions.js
import { fetchData } from '../api/fetchData';
import { urls } from '.../constants';
export function fetchChartData(){
return (dispatch) => {
dispatch(fetchChartDataStart());
return Promise.all(urls.map((url) =>
fetchData(url)
.then((json) => dispatch(receiveChartData(json)))
.catch((err) => dispatch(fetchChartDataError(err))));
}
}