Как реализовать кнопки, которые получают разные данные от API в зависимости от того, какая кнопка нажата в Redux? - PullRequest
0 голосов
/ 05 ноября 2019

В настоящее время у меня есть код, который отображает данные API на странице. Это список:

API имеет такую ​​структуру:

{"hij":{
"low":[{......},{.....}],
"all":[{....},{......}]}
}

Как реализовать такие кнопки на Redux? Можете ли вы помочь мне немного? Я посмотрел несколько десятков видео на YouTube, прочитал много статей и не нашел примеров того, как создавать кнопки, которые бы брали разные данные из API .... В React я реализую это следующим образом (App.js):

class App extends React.Component {
  state = {
    day: 1,
    data: [],
    filteredData: [],
    search: "",
    shift: "low"
  };

  componentDidMount() {
    this.fetchData();
  }

  fetchData = async () => {
    const response = await fetch(`...`);
    const data = (await response.json()).body;
    this.setState({data, shift: Object.keys(data)[0]}, this.filter);
  };

  loadDay = day => {
    this.setState({ day }, this.fetchData);
  };

  updateSearch = e => {
    this.setState({search: e.target.value});
  };

  filter = () => {
    this.setState(({ search, data, shift }) => {
      const s = search.toLowerCase();
      return {
        filteredData: data[shift].filter(n =>
          n.term.toLowerCase().includes(s)
        )
      };
    });
  };

  onClick = ({target: { dataset: { shift }}}) => {
    this.setState(() => ({ shift }), this.filter);
  };

  render() {
    const { search, shift, data, filteredData } = this.state;

    return (
      <div>
        <TableSearch value={search}
           onChange={this.updateSearch} 
            onSearch={this.filter}/>

      {days.map((day, i) => (
             <button key={day} 
             onClick={() => this.loadDay(i)}
             className={i === this.state.day ? "active" : ""}>{day}</button>
         ))}
        <br />
        {Object.keys(data).map(n => (
             <button data-shift={n}
               onClick={this.onClick}
               className={n === shift ? "active" : ""}>{n} shift</button>
        ))}
        <TableData data={filteredData} />
      </div>
    );
  }
}



1 Ответ

2 голосов
/ 05 ноября 2019

Есть несколько вещей, которые нужно изменить, чтобы сделать это совместимое с редуксом приложение, меньше всего вас беспокоили бы кнопки. Поэтому вместо того, чтобы отвечать непосредственно на кнопку, вот аннотированный рефакторинг вашего приложения в 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>
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...