Redux Thunk with local state

Redux Thunk with local state
0

#1

I have this app which currently fetches some posts from an API using Thunk. I need to filter these by the criteria stored in the state in my searchBar component when the search button is pressed, using Reselect. I know I have to adapt my reducer to “accept” the local state of my SearchBar component, but I´m a bit lost on how to set it up and on how to use ReSelect. Could anyone help?

app component

class ItemList extends Component {
componentDidMount() {
this.props.fetchData('https://football-players-b31f2.firebaseio.com/players.json');
  }
render() {
if (this.props.hasErrored) {
return <p>Sorry! There was an error loading the items</p>;
      }
if (this.props.isLoading) {
return <p>Loading…</p>;
      }
return (
<SearchBar items={this.props.items}/>
      );
  }
}
const mapStateToProps = (state) => {
return {
      items: state.items,
      hasErrored: state.itemsHasErrored,
      isLoading: state.itemsIsLoading
  };
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: (url) => dispatch(itemsFetchData(url))
  };
};
export default connect(mapStateToProps, mapDispatchToProps)(ItemList);

SearchBar component

class SearchBar extends Component {
  constructor () {
    super();
    this.state = {
      age: '',
      name: '',
      selected: "position"
    };
    this.handleChange = this.handleChange.bind(this);
this.handleSelectChange=this.handleSelectChange.bind(this)
  }

  handleChange (evt) {
    this.setState({ [evt.target.name]: evt.target.value });
  }

    handleSelectChange (evt) {
    this.setState({selected: event.target.value});
  }

  render () {
const unique = [...new Set(props.items.map(item => item.position))];
       const items = unique.map((i, index) =>{return ( <option value={i} key={index}> {i}</option> )
      });
   return (
      <div>
        <input type="text" name="name" 
          pattern= "/[a-zA-Z]+" onChange={this.handleChange} />
        <input type="number" name="age" 
         min="18" max="40" onChange={this.handleChange} />
 <React.Fragment>
  <select onChange={this.handleSelectChange} value={this.state.selected}>{items}</select>
 </React.Fragment>
       <button>Search</button>
        </div>
    );
  }
}

Reducer

export default combineReducers({
  items,
  itemsHasErrored,
  itemsIsLoading
});
export function itemsHasErrored(state = false, action) {
switch (action.type) {
case 'ITEMS_HAS_ERRORED':
return action.hasErrored;
default:
return state;
  }
}
export function itemsIsLoading(state = false, action) {
switch (action.type) {
case 'ITEMS_IS_LOADING':
return action.isLoading;
default:
return state;
  }
}
export function items(state = [], action) {
switch (action.type) {
case 'ITEMS_FETCH_DATA_SUCCESS':
return action.items;
default:
return state;
  }
}

Actions

export function itemsHasErrored(bool) {
return {
      type: 'ITEMS_HAS_ERRORED',
      hasErrored: bool
  };
}
export function itemsIsLoading(bool) {
return {
      type: 'ITEMS_IS_LOADING',
      isLoading: bool
  };
}
export function itemsFetchDataSuccess(items) {
return {
      type: 'ITEMS_FETCH_DATA_SUCCESS',
      items
  };
}
export function itemsFetchData(url) {
return (dispatch) => {
dispatch(itemsIsLoading(true));
fetch(url)
          .then((response) => {
if (!response.ok) {
throw Error(response.statusText);
              }
dispatch(itemsIsLoading(false));
return response;
          })
          .then((response) => response.json())
          .then((items) => dispatch(itemsFetchDataSuccess(items)))
          .catch(() => dispatch(itemsHasErrored(true)));
  };
}