I am really new to Reac.js/Redux.js and javascript in general. I am trying to learn a new language by actually doing it. I am trying to build a simple app that lets you search for the product. Eventually, I will create additional features that will allow a user to add and to remove the items form the list of products.
So far, I have built two containers: ListOfProd and Search. Everything works except I can’t figure out how filter the list of products based on the search criteria entered by a user. Where would be the best place to implement filter? and What would be the best way to filter the array of objects based on the search criteria? Please let me know how I can improve my code!
Container Search.js
import React, {Component} from 'react';
import {bindActionCreator} from 'redux';
import {connect} from 'react-redux';
//import scroll for search
//import Scroll from './components/Search/Scroll';
import SearchBox from '../components/Search/SearchBox';
//import action for search
import {setSearchField} from '../actions/actionSearch';
//list of prod
import ListOfProd from './ListOfProd';
const mapStateToProps = state =>{
return{
product: state.product,
searchField: state.searchField
}
}
const mapDispatchToProps = (dispatch) => {
return{
onSearchChange: (event) => dispatch(setSearchField(event.target.value))
}
}
class Search extends React.Component{
render(){
const {searchField, onSearchChange} = this.props;
// const filterProduct = this.props.product.filter(product =>{
// return product.prod.includes(searchField);
// })
return(
<div className = 'tc'>
<SearchBox searchChange={onSearchChange}></SearchBox>
<ListOfProd></ListOfProd>
</div>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Search);
Container ListOfProd.js
// import Component
// hook it up to data store
import React, {Component} from 'react';
import {bindActionCreator} from 'redux';
import {connect} from 'react-redux';
//import Search from 'Search';
class ListOfProd extends React.Component {
createListItems(){
console.log(this.props.product);
return this.props.product.map((product, i) => {
console.log(this.props.product.prod);
console.log(this.props.searchField);
return(
<li key={i}>{product.prod} {product.price}</li>
)
});
}
render(){
return(
<ul>
{this.createListItems()}
</ul>
)
}
}
const mapStateToProps = state =>{
return{
product: state.searchProd.product,
searchField: state.searchProd.searchField
}
}
export default connect(mapStateToProps)(ListOfProd);
Actions
import {CHANGE_SEARCH_FIELD} from '../constants/constants';
export const setSearchField = (text) => ({
type: CHANGE_SEARCH_FIELD,
payload: text
})
Reducer ReducerSearch.js
import {CHANGE_SEARCH_FIELD} from '../constants/constants';
import React from 'react';
const initialState = {
searchField: '',
product : [
{
id: 1,
prod: "prod1",
price: "5"
},
{
id:2,
prod: "prod2",
price: "5"
}
]
}
export const searchProd = (state = initialState, action={}) =>{
console.log(action.payload);
console.log(action.type);
switch(action.type){
case CHANGE_SEARCH_FIELD:{
console.log(action.payload);
console.log(state.product);
return {...state, searchField: action.payload};}
default:
return state;
}
}
App.js
import React, { Component } from 'react';
import SignIn from './components/SignIn/SignIn';
import Register from './components/Register/Register';
import ListOfProd from './containers/ListOfProd';
import Search from './containers/Search';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<Search></Search>
</div>
);
}
}
export default App;
Pleae let me know if you need to see my components.
In general, the best way to implement of filtration is on the key-down event on your text-box.
but before that you have to check your data source and think about your performance, you can set a key limitation or some other limitation.
for your second question, I should say that if your array is in your client use map to have the best performance but you have to get it from a server you can do many things
Related
I am new to using redux for React Native and am testing it with a simple case. I have been able to successfully connect to the store, and I can see the action is dispatched properly using the redux debugger, however, the store is not updating in the debugger. I've tried several different implementations, but nothing is working. Any help would be appreciated!
Component:
import React, { PureComponent } from 'react'
import { Text, TouchableOpacity, SafeAreaView, Alert, Button } from 'react-native'
import { Navigation } from 'react-native-navigation';
import { connect } from 'react-redux'
import simpleAction from '../store/actions/simpleAction'
class App2 extends PureComponent {
constructor(props){
super(props);
}
pressRedux = () => {
const data = 'hello'
this.props.simpleAction(data)
}
render() {
return (
<SafeAreaView>
<Text>
{this.props.state.simpleReducer.text}
</Text>
<Button onPress = {this.pressRedux} title = 'Redux' />
</SafeAreaView>
)
}
}
function mapStateToProps(state) {
return {
state: state
};
}
const mapDispatchToProps = {
simpleAction
}
export default connect(mapStateToProps, mapDispatchToProps)(App2);
Action:
import {SET_TEXT} from '../types/types'
export default function simpleAction(data) {
return({
type: SET_TEXT,
payload: data
})
}
reducer:
import SET_TEXT from '../types/types'
const INITIAL_STATE = {
text: 'Hi'
}
const simpleReducer = (state = INITIAL_STATE, action ) => {
switch(action.type){
case SET_TEXT:
return { ...state, text: action.payload};
default:
return state;
}
}
export default simpleReducer;
The code you've shared here looks correct. Only thing I can suggest is, if you're seeing the action come through in the debugger, your issue is either with the data/payload or logic within simpleReducer.
In this case you have it properly stripped down so I'd almost think this isn't actually the code you are running, it might be something in your build process?
thanks in advance!!
I'm in trouble, I dont know whats wrong with my map hehe. I'm a new student (JS, React, Redux). It'd should show a list (or at least one name, anything), but nothing happen.
import React, {Component} from "react";
import { connect } from "react-redux";
import { push } from "connected-react-router";
import { getTrips } from "../../actions/allActions";
import List from "#material-ui/core/List";
class ListTrips extends Component {
componentDidMount() {
this.props.getTripsAction();
}
render() {
return (
<List>
{
this.props.trips.map((trip) => {
return(<li>{trip.name}</li>)
})
}
</List>
);
}
}
const mapStateToProps = state => ({
trips: state.trips.trips
});
const mapDispatchToProps = dispatch => ({
getTripsAction: () => dispatch(getTrips()),
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(ListTrips)
I have been building a React-Redux application to display some weather data (openweathermap.org API) if a button gets clicked.
Somehow when the Container is rendered the data are not arriving, even if I managed to handle the promise using Axios.
As you can see in the console.log, the 'tempo' object is empty once it arrives in the container. Then, once the button is clicked, the request correctly arrives on the container and 'tempo' gets the data I want to render.
The problem occurs when I try to access those properties arrived after that the onClick() event was fired. They do not exist yet, so the whole components throw an error.
I think there is some problem with the async await response managed in the Axios request but I cannot find it.
Sorry if the explanation was not properly technical.
I remain at disposal for clarifications.
Action Creator with the API request
import axios from 'axios';
export const GET_CECCIOLA = 'GET_CECCIOLA';
export function submitWeather() {
const url = 'https://api.openweathermap.org/data/2.5/weather?appid=ce6111c5cb481755173214d6bf62f51a&q=Cecciola,it';
const cecciola = axios.get(url);
return {
type: 'GET_CECCIOLA',
payload: cecciola
}
}
Container responsible for the rendering when button is clicked
import React, { Component } from 'react';
import {connect} from 'react-redux';
class CecciolaTime extends Component {
render() {
console.log(this.props.tempo)
return (
<div>
<h2>{this.props.tempo}
</h2>
</div>
);
}
}
function mapStateToProps ({ tempo }) {
return { tempo };
}
export default connect(mapStateToProps)(CecciolaTime);
Container with the onClick() method
import React, {Component} from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import {submitWeather } from '../actions/index';
class SearchBar extends Component {
constructor(props) {
super(props)
this.getWeather = this.getWeather.bind(this);
}
getWeather(e) {
e.preventDefault();
this.props.submitWeather(e);
}
render() {
return (
<form>
<button onClick={this.getWeather}>
tempo a Cecciola
</button>
</form>
)
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ submitWeather }, dispatch);
}
export default connect(null, mapDispatchToProps)(SearchBar);
Reducer
import { GET_CECCIOLA } from '../actions/index';
export default function(state = [], action) {
switch (action.type) {
case GET_CECCIOLA:
return [action.payload.data, ...state];
}
return state;
}
Reducer_Index
import { combineReducers } from 'redux';
import CecciolaReducer from './cecciola_reducer';
export default combineReducers({
tempo: CecciolaReducer
})
Store (I am using Redux-Promise as middleware)
import React from 'react';
import './index.css';
import App from './components/App';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './reducers'
import ReduxPromise from 'redux-promise';
const storeWithMiddleware = applyMiddleware(ReduxPromise)(createStore);
render(
<Provider store={storeWithMiddleware(rootReducer)}>
<App />
</Provider>,
document.getElementById('root')
)
If you are trying to display non-existing property in tempo object and it fails - the most common way to handle it - just check if this property exists, like that:
import React, { Component } from 'react';
import {connect} from 'react-redux';
class CecciolaTime extends Component {
render() {
const { name } = this.props.tempo
return (
<div>
{/* Check if name exists then display */}
<h2>{name && name}</h2>
</div>
);
}
}
function mapStateToProps ({ tempo }) {
return { tempo };
}
export default connect(mapStateToProps)(CecciolaTime);
NOTE: You're trying to render an object { this.props.tempo } in h2 tag, which can cause another error.
UPDATE (from comments): I've find the issue, it was because you're setting result into array and it's actually keeped in 0 index in array. So you can access to your variables via this.props.tempo[0].name. To avoid this mess just use object instead of array as initial state, it's much easier to handle then.
I've created sandbox for you with working code (click to see).
Hope it will helps.
I'm a bit confused about redux implementation.
Let's say my app has this component structure:
-App
--ProfilationStep
---ProfilationStep1
----React-Select (http://jedwatson.github.io/react-select/)
I need to use redux because the app is going to grow bigger and deeper, so I started by setting up Actions, Reducers and Action types for the React-Select component. I also set the mapStateToProps in the App.js file.
Now I need to know how to pass/access the data stored in redux to other components (React-Select for example) and how to edit it with the actions I declared.
This is my index.js file
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import ProfilationSelectReducer from './components/reducers/profilationSelect';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
const store = createStore(
ProfilationSelectReducer
);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
registerServiceWorker();
This is my App.js
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import { bindActionCreators} from 'redux'
import Profilation from './components/Profilation'
import ProfilationStep from './components/Profilation/ProfilationStep'
import { connect } from 'react-redux';
import * as SelectActionCreators from './components/actions/profilationSelect'
import 'react-select/dist/react-select.css';
class App extends Component {
static propTypes = {
steps: PropTypes.array.isRequired
};
render() {
console.log(this.props)
const { dispatch, steps } = this.props;
const changeValue= bindActionCreators(SelectActionCreators.changeValue, dispatch);
const stepComponents = this.props.steps.map((step, index) => (
<ProfilationStep
key={index}
index={index}
step={step}
/>
));
return (
<div className="repower-app">
{ stepComponents }
</div>
);
}
}
const mapStateToProps = state => ({
steps:state.steps
});
export default connect(mapStateToProps)(App);
This is my ProfilationStep.js file
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import ProfilationStep1 from './ProfilationStep1'
import ProfilationStep2 from './ProfilationStep2'
import ProfilationStep3 from './ProfilationStep3'
import ProfilationStep4 from './ProfilationStep4'
import ProfilationStep5 from './ProfilationStep5'
const ProfilationStep = props =>
<div className='ProfilationStep'>
{props.index===0 &&
<ProfilationStep1
step={props.step}
/>
}
{props.stepIndex===2 &&
<ProfilationStep2
handleSelect={props.handleSelect}
handleInput={props.handleInput}
expend={props.expend}
period={props.period}
light={props.light}
gas={props.gas}
/>
}
{props.stepIndex===3 &&
<ProfilationStep3
handleSelect={props.handleSelect}
environment={props.environment}
/>
}
{props.stepIndex===4 &&
<ProfilationStep4
flexibility={props.flexibility}
handleSelect={props.handleSelect}
/>
}
{props.stepIndex===5 &&
<ProfilationStep5
customize={props.customize}
handleSelect={props.handleSelect}
/>
}
</div>
export default ProfilationStep
This is my ProfilationStep1.js file
import React, { Component } from 'react';
import Select from 'react-select';
import PropTypes from 'prop-types'
var jobOptions = [
{ value: 'edilizia', label: 'Edilizia' },
{ value: 'editoria', label: 'Editoria' },
{ value: 'educazione', label: 'Educazione' }
];
const ProfilationStep1 = props =>
<div className='ProfilationStep'>
La mia attivitĂ si occupa di <Select
name="job"
value={props.step.job}
onChange={e => props.changeValue(e.target.value)}
options={jobOptions}
/>
</div>
ProfilationStep1.propTypes = {
//isComplete: PropTypes.bool.isRequired,
//isActive: PropTypes.bool.isRequired
job: PropTypes.string.isRequired,
service: PropTypes.string.isRequired,
handleSelect: PropTypes.func.isRequired
}
export default ProfilationStep1
This is my reducer
import * as ProfilationSelectActionTypes from '../actiontypes/profilationSelect';
const initialState = {
steps: [{
job: "",
service: ""
}],
}
export default function ProfilationSelectReducer (state=initialState, action){
switch(action.type){
case ProfilationSelectActionTypes.CHANGE_VALUE:
return {
...state,
steps:[{
job: action.value
}]
};
default:
return state;
}
}
This is my actiontypes file
export const CHANGE_VALUE ='profilationSelect/CHANGE_VALUE';
and, finally, this is my actions file
import * as ProfilationSelectActionTypes from '../actiontypes/profilationSelect';
export const changeValue = value =>{
return{
type: ProfilationSelectActionTypes.CHANGE_VALUE,
value
}
}
Thank you for any help
You are definitely on the right way.
The solution is simple: You bind your state to the react props. With the props, you can do whatever you like (e.g. pass them to react-select). If you want to modify it, you have to map "mapDispatchToProps", where you map functions, which execute your actions to the props. This works the same as "mapStateTopProps":
End of App.js (import your actions file on top, named "profilationSelectActions" here):
const mapStateToProps = state => ({
steps:state.steps
});
const mapDispatchToProps = dispatch => ({
updateJobValue: (value) => dispatch(profilationSelectActions.changeValue(value))
}
// Also add here mapDispatchToProps
export default connect(mapStateToProps, mapDispatchToProps)(App);
Now the function "updateJobValue" is available in the props of your app.js. You can now easily pass it down to your components and to the onChange event of react-select:
In your ProfilationStep1.js change this line:
onChange={e => props.changeValue(e.target.value)}
To this (after you passed the function updateJobValue down)
onChange{e => props.updateJobType(e.target.value)}
After that, updateJobType should go all the way up to App.js and then dispatch the action. After that, the application will re-render with the new steps.
I am starter in react & redux. I want to make todolist app. but when I insert a list into a store the displayList() function is not re-render. How can I fix this.
This is my reducer code.
export default function(state = ['start1','start2'], actions) {
switch(actions.type) {
case 'APPEND_ITEM':
state.push(actions.payload.item)
return state
break
}
return state
}
And this is my todolist.js code.
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import ReactDOM from 'react-dom'
import React from 'react'
class TodoList extends React.Component {
displayList(){
return this.props.dispatchs.map((item) => {
return(
<li key={ Math.random() }>{item}</li>
)
})
}
render(){
return(
<div>
{ this.displayList() }
</div>
)
}
}
var mapStateToProps = (state) => {
return {
dispatchs: state.dispatch
}
}
export default connect(mapStateToProps)(TodoList)
pin 2,3 does not re-render on the screen
Thank you for help.
Instead of using push in the reducer, return [ ... state, action.payload.item ]
case 'APPEND_ITEM':
return [ ...state, action.payload.item ]
This is because React will see the new state (object reference) equal to the old one, and decide not to re-render since it seems like nothing have changed