I have a Rails backend, with a list of ingredients. I am trying to use a Search Bar (form) to input an ingredient ID to find the appropriate ingredient. When I click the submit button of the form, I want the dispatch function getIngredient, with ID as argument, but with the approaches I have tried, I am not getting what is supposed to be the ID; it is undefined, or simply "an event". I only saw the error message briefly, so I don't have more details then that. It simply refreshes state, erasing the error messages.
I have tried having the value of the form onSubmit={() => getIngredient(id)}
, it then returns as an event object. with onSubmit={() => this.props.getIngredient(id)}
it returns undefined. Stating it simply as onSubmit={getIngredient(id)}
also didn't work.
I have console.logged everything, and I found that it errors when it hits the dispatch action in getIngredient(id)
, because the id is undefined.
The getIngredients method I have works, it was when trying to only grab one ingredient I have had trouble. I have read everything I could find about redux, react-redux, and even reselect to try and target the issue, and I have hit this wall.
IngredientForm.js component:
<form onSubmit={(id) => getIngredient(id)}>
<label value="Find Ingredient">
<input type="text" placeholder="Search By Id" />
</label>
<input type="submit" value="Find Ingredient" />
</form>
const mapDispatchToProps = { getIngredient }
const mapStateToProps = (state, props) => {
const id = props.id;
return {
ingredients: state.ingredients.filter(ingredient => ingredient.id === id)
};
};
Dispatch action creator in actions.js:
export function getIngredient(id) {
return dispatch => {
console.log("trying to get id to show up =>", id)
dispatch(getIngredientRequest(id));
return fetch(`v1/ingredients`)
.catch(error => console.log(error))
.then(response => response.json())
.then(json => dispatch(getIngredientSuccess(json)))
.catch(error => console.log(error));
}
}
action:
export function getIngredientRequest(id) {
return { type: GET_INGREDIENT_REQUEST, id };
}
reducer.js
function rootReducer(state = initialState, action) {
console.log(action.type);
switch (action.type) {
case "GET_INGREDIENTS_SUCCESS":
return { ...state, ingredients: action.json.ingredients }
case "GET_INGREDIENTS_REQUEST":
console.log('Ingredients request received')
return
case "HIDE_INGREDIENTS":
console.log('Ingredients are being hidden')
return { ...state, ingredients: [] }
case "GET_INGREDIENT_REQUEST":
console.log('One Ingredient request received:', "id:", action.id)
return
case "GET_INGREDIENT_SUCCESS":
console.log('GET_INGREDIENT_SUCCESS')
return {
...state,
ingredients: action.json.ingredients.filter(i => i.id)
}
default:
return state
}
}
Server terminal window output:
Processing by StaticController#index as HTML
Parameters: {"page"=>"ingredients"}
Rendering static/index.html.erb within layouts/application
Rendered static/index.html.erb within layouts/application (0.9ms)
Completed 200 OK in 9ms (Views: 7.9ms | ActiveRecord: 0.0ms)```
That's because in React Synthetic Events - like onSubmit
- the first parameter in the callback is always the Event
object.
I recommend you to use controlled inputs. That means you keep the id value in the component's state and assign that value to the input. Whenever the user types a new id, you update the state and assign the new value to the input.
class Form extends React.Component {
state = {
id: ""
};
handleInputChange = event => {
this.setState({ id: event.target.value });
};
render() {
return (
<form
onSubmit={(event) => {
event.preventDefault();
getIngredient(this.state.id);
}}
>
<label value="Find Ingredient">
<input
type="text"
placeholder="Search By Id"
onChange={this.handleInputChange}
value={this.state.id}
/>
</label>
<input type="submit" value="Find Ingredient" />
</form>
);
}
}