Есть несколько вещей, которые нужно изменить, чтобы сделать это совместимое с редуксом приложение, меньше всего вас беспокоили бы кнопки. Поэтому вместо того, чтобы отвечать непосредственно на кнопку, вот аннотированный рефакторинг вашего приложения в Redux:
import { createStore, applyMiddleware } from 'redux';
import { connect, Provider } from 'react-redux';
import thunk from 'redux-thunk';
// Take out common functionality into seperate functions, such as
// running a search here.
function searchFilter (search, data) {
return data.filter(n => n.term.toLowerCase().includes(search));
}
// This is your reducer function which updates the global redux state,
// depending on which action you dispatch:
// see https://redux.js.org/basics/reducers
function reducer (state = {}, action) {
state = { ...state }
switch (action.type) {
case 'SET_SEARCH':
state.search = action.search.toLowerCase();
break;
case 'RUN_FILTER':
state.shift = action.shift || state.shift;
state.search = action.search || state.search;
state.filteredData = searchFilter(state.search, state.data[state.shift]);
break;
case 'LOAD_DATA_START':
state.day = action.day;
break;
case 'LOAD_DATA_END':
state.data = action.data;
state.shift = Object.keys(data)[0];
state.filteredData = searchFilter(state.search, state.data[state.shift]);
break;
}
return state;
}
// This is your store object which contains an initial state, and a reducer
// that will be used for dispatched actions.
// see https://redux.js.org/basics/store
//
// Redux-thunk is used as middleware to support async data fetching which you will
// also need to read up on, although you don't really need to know how it
// works at first.
// see https://github.com/reduxjs/redux-thunk
const store = createStore(
reducer,
{
day: 1,
data: [],
filteredData: [],
search: "",
shift: "departure"
},
applyMiddleware(thunk)
);
// This is a "thunk" called fetch data, again you can read more
// about thunks in the redux-thunk docs
// see https://github.com/reduxjs/redux-thunk
function fetchData (day) {
return async (dispatch) => {
dispatch({ type: 'LOAD_DATA_START', day });
const response = await fetch(`https://api.iev.aero/api/flights/${days[this.state.day]}`);
const data = (await response.json()).body;
dispatch({ type: 'LOAD_DATA_END', data });
}
}
const days = ["23-08-2019", "24-08-2019", "25-08-2019"];
// Stripped down component, it does not handle any of its own state
// all state is passed to it through the redux connect HOC.
class Root extends React.Component {
componentDidMount() {
this.props.onFetchData(this.props.day);
}
render() {
const { search, shift, data, filteredData, onFilter, onSetSearch, onFetchData } = this.props;
return (
<div>
<TableSearch value={search}
onChange={(e) => onSetSearch(e.target.value)}
onSearch={() => onFilter()} />
{days.map((day, i) => (
<button key={day}
onClick={() => onFetchData(day)}
className={i === day ? "active" : ""}>{day}</button>
))}
<br />
{Object.keys(data).map(n => (
<button data-shift={n}
onClick={(e) => onFilter({ shift: e.target.dataset.shift })}
className={n === shift ? "active" : ""}>{n} shift</button>
))}
<TableData data={filteredData} />
</div>
);
}
}
// This is the "connected" version of the component, which is
// your component wrapped in a connect HOC. When the reducer function
// is run, the two functions below will be executed and your component
// inside will re render.
//
// You can read more about this one in react-redux
// https://react-redux.js.org/
const ConnectedRoot = connect(
(state) => state,
(dispatch) => ({
onFilter: (args) => dispatch({ type: 'RUN_FILTER', ...args }),
onSetSearch: (search) => dispatch({ type: 'SET_SEARCH', search }),
onFetchData: (day) => dispatch(fetchData(day))
})
);
// This is your top level component that you would call in ReactDOM.render
// The Provider component is part of react-redux, and you can read about it
// there, but in most cases it is sufficient to drop it at the very top level
// of your application.
// https://react-redux.js.org/
const App = () => (
<Provider store={store}>
<ConnectedRoot />
</Provider>
);