How to make a Search Bar using React Native with Redux - reactjs

I want to make a search bar for searching items from the list using react native with redux
I have tried this :
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Text, View, FlatList, Image, ScrollView, StyleSheet, TouchableOpacity, TextInput} from 'react-native';
import { SearchBox, Spinner } from './common';
import { listShow, searchResult} from './actions';
class flatRedux extends Component {
componentWillMount() {
this.props.listShow();
}
_onSearchChange = text => {
this.props.searchResult(text)
this.props.listShow(text)
}
render() {
console.log(this.props);
return (
<View style={styles.MainContainer}>
<SearchBox
placeholder="Search..."
onChangeText={this._onSearchChange}
/>
<FlatList
data={this.props.flatlist}
ItemSeparatorComponent = {this.FlatListItemSeparator}
keyExtractor={(item, index) => index.toString()}
renderItem={({item}) =>
<Text key={item.id} style={styles.FlatListItemStyle} >
{item.cl_name} </Text>}
/>
</View>
);
}
}
const mapStateToProps = state => {
return {
search: state.searchResult.search,
flatlist: state.listShow.flatlist
};
};
export default connect(mapStateToProps, { listShow, searchResult })(flatRedux);
This is the SearchAction file
import { SEARCH_DATA } from './types'
export const searchResult = (text) => {
return {
type: SEARCH_DATA,
payload: text
};
}
And this one is SearchReducer File
import {SEARCH_DATA} from "../actions";
const INITIAL_STATE = {
search: ''
}
export default (state = INITIAL_STATE, action) => {
console.log(action);
switch(action.type) {
case SEARCH_DATA:
return {
...state,
search: action.payload
}
default:
return state;
}
}
And files who are fetching items from the localhost server are below :
flatAction.js
import axios from 'axios';
import { FLAT_DATA } from './types';
export const listShow = () => {
return (dispatch) => {
axios.post('http://192.168.48.228/reactTest/list.php')
.then((response) => {
dispatch({
type: FLAT_DATA,
payload: response.data
});
})
.catch((error) => {
console.log(error);
});
};
};
flatReducer.js
import {FLAT_DATA } from '../actions/types';
const INITIAL_STATE = {
flatlist: '',
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case FLAT_DATA:
return { ...state, flatlist: action.payload };
default:
return state;
}
};
All items are fetching but 'Search' is not working for them.

'Search' is not working for them?
it's not detailed enough to give a specific answer.
To debug the workflow try changing the endpoint of listShow to search and then calling this.props.listShow(text) on input onChange handler the see if the redux part is properly connected
assuming,
All items are fetching
If it is not working need to see if your keyListners are working or not (need to see the code for searchbox), and finally, if the flatlist is rerendered (It doesn't rerender if shallow comparison fails)

Related

Rendering text on a page from the redux-store

I have a text input in React-Native component page and I send the input text to the store.
I am trying to render the input text on the page from the redux store but it will not display.
Below are my component and my redux store. Am I not calling the value correctly in my component with this.props.email?
COMPONENT
import React, { Component} from 'react';
import { StyleSheet, View, Button, Text, StatusBar, TextInput, TouchableOpacity, Image } from 'react-native';
import { connect } from 'react-redux';
class Counter extends Component {
email(value) {
this.props.email(value);
}
toggleCounterHandler() {}
render() {
return (
<View>
<View ><Text style={styles.welcometext}>{this.props.email}</Text></View>
<View>
<TextInput
style={styles.input}
onChangeText = {(value) => this.props.email(value)}
value={this.props.value}
/>
</View>
</View>
);
}
}
const mapStateToProps = (state) => {
return {
value: state.value
};
}
const mapDispatchToProps = dispatch => {
return {
email: (value) => dispatch({
type: 'email',
payload: value
})
}
};
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
REDUX-STORE
import React from 'react';
import { createStore } from 'redux';
const counterReducer = (state = { email:'email' }, action) => {
if (action.type === 'email') {
return {
email: action.payload,
};
}
return state;
};
const store = createStore(counterReducer);
export default store;

expo React-native data not rendering but logs in console

I was fetching data from API it's working fine, using react-native with expo I'm using redux it was working file with single reducer but when I used combined reducers it's stops rendering but still able to log all data in console, I'm not sure what I'm doing wrong I have been facing this issue for days.
I have tried:
reinstalling expo
upgrading expo
recreating new project
I have searched the internet but I have been unable to find any solution
Reducer
import {
PRODUCT_DETAILS_REQUEST,
PRODUCT_DETAILS_SUCCESS,
PRODUCT_DETAILS_FAIL,
} from "../../../constants";
const initialState = [];
const productDetailsReducer = (state = initialState, action) => {
switch (action.type) {
case PRODUCT_DETAILS_REQUEST:
return { loading: true };
case PRODUCT_DETAILS_SUCCESS:
return { loading: false, product: action.payload };
case PRODUCT_DETAILS_FAIL:
return { loading: false, error: action.payload };
default:
return state;
}
};
export default productDetailsReducer;
component
import React, { useEffect } from 'react'
import { StyleSheet, ScrollView, Linking, Text, View, Image } from "react-native";
import { Card, Button } from "react-native-elements";
import { useSelector, useDispatch } from 'react-redux'
import { getProduct } from '../Redux/actions/products.Action.js'
export const Product = ({ route }) => {
const { itemId } = route.params;
// 376
const dispatch = useDispatch()
const storeState = useSelector((state) => state.productDetailsReducer);
const {product, loading, error} = storeState;
const printdata = () => {
console.log(product.name);
}
useEffect(() => {
dispatch(getProduct(itemId));
}, [dispatch]);
return (
<>
<Text> {loading ? "loading" : product.name}</Text>
<Button onPress={() => { printdata() }}>press</Button>
</>
)
}
export default Product
error
state
change
const initialState = [] to const initialState = {}
const printdata = () => {
console.log(product?.name); // check is product exists then console.log(product.name)
}

Redux - mapStateToProps not working (React-Native)

I am learning Redux and can't seem to get state to display in my home page. I get the error: 'undefined is not an object, evaluating this.props.titles.allTitles. The error is located in Home created by connect function' Here is the code, let me know if you need any other files. Thank you. I am adding more text to comply with stack overflow, thank you for your help.
home:
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import { connect } from 'react-redux'
class Home extends React.Component {
render() {
return (
<View>
<Text>Redux Test</Text>
<Button
title='+ new list'
onPress={() =>
this.props.navigation.navigate('New List')
}
/>
<Text>{this.props.titles.allTitles.length}</Text>
</View>
)
}
}
const mapStateToProps = (state) => {
const { titles } = state
return { titles }
};
export default connect(mapStateToProps) (Home);
```
reducer:
```
import { combineReducers } from 'redux';
const INITIAL_STATE = {
allTitles: []
};
const tagReducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case 'NEW_LIST':
return {
...state,
allTitles: [...state.allTitles, action.payload.title]
}
default:
return state;
}
};
const reducers = combineReducers({
tagReducer
})
export default reducers;
```
import React from 'react';
import { StyleSheet, Text, View, Button, TextInput } from 'react-native';
import { connect } from 'react-redux';
import { newList } from '../store/tagActions';
class List extends React.Component {
constructor(props){
super(props);
this.state = {
title: ''
}
}
render() {
return (
<View style={styles.container}>
<TextInput
style={styles.title}
placeholder='add Title..'
onChangeText={text => this.setState( {title: text} ) }
/>
<Button
title='done'
onPress={() => {
this.props.newList(this.state.title)
}
}
/>
<Text>{this.state.title}</Text>
</View>
)
}
}
const mapStateToProps = (state) => {
const { allTitles } = state
return { allTitles }
};
export default connect(mapStateToProps, { newList }) (List);
In your reducer, you have the following -
allTitles: [...state.allTitles, action.payload.title]
When you do, I don't see title in the redux state.
const mapStateToProps = (state) => {
const { titles } = state
return { titles }
};
You need to do
const mapStateToProps = (state) => {
const { allTitles } = state
return { allTitles }
};
Then do {this.props.allTitles.length} inside the render statement
Getting Redux setup can be pretty tricky in my opinion. After taking a look at your code I created a small React-Native project and setup Redux as closely as possibly to what you described in your question. Hopefully my answer helps. Please note that all three the files in my answer (App.js, Home.js, & titleReducer.js) are contained in the same directory.
App.js
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import titleReducer from './titleReducer';
// React-Redux
import {
createStore,
combineReducers,
} from 'redux';
import {
connect,
Provider
} from 'react-redux';
// Import Components (Screens)
import Home from './Home';
// Intialize Redux Store
const rootReducer = combineReducers({
titles: titleReducer
});
const store = createStore(rootReducer);
class App extends React.Component {
render() {
return (
<Provider store={store}>
<Home/>
</Provider>
)
}
}
export default App;
titleReducer.js
const initialState = {
allTitles: [],
};
const titleReducer = (state, action) => {
// check for state undefined to prevent
// redux from crashing app on load
if (typeof state === 'undefined') {
return {...initialState};
}
switch (action.type) {
case 'ADD_TITLE':
const newState = {...state};
const newTitle = action.payload;
newState.allTitles.push(newTitle);
return newState;
default:
return {...state};
}
// If none of the conditions above are true,
// simply return a copy of the current state
return {...state};
};
export default titleReducer;
Home.js
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import {
connect,
Provider
} from 'react-redux';
function randomTitle() {
return Math.random().toString();
}
class Home extends React.Component {
render() {
return (
<View>
<Text>Redux Test</Text>
<Button
title="Add Title"
onPress={ () => this.props.addTitle(randomTitle()) }/>
<Text>{this.props.titles.allTitles.length}</Text>
</View>
)
}
}
const mapDispatchToProps = dispatch => {
return {
addTitle: (payload) => dispatch({type: 'ADD_TITLE', payload: payload}),
};
};
const mapStateToProps = (state) => {
return {
titles: state.titles,
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Home);
I think you've forgot to define a store for your app. Go to your root class (app.js or something) and define your reducers to your store:
const store = createStore(tagReducer)
or if you have multiple reducers you can combine them in one line:
const store = createStore(combineReducers({
tag: tagReducer,
someOther: otherReducer
}));
Hope that it fixes your problem.

React Native can't read Database Firebase

I can't read database to insert in 'Text'. I'm using Redux
Json
DiasSemana
|
|__Quarta: "Test Program"
|
|__Quinta: "nothing"
|
|
Class EstudoDia.js I used mapStateToProps, connect and import actions.
import React, { Component } from "react";
import { View, Text } from "react-native";
import { Actions } from "react-native-router-flux";
import { connect } from "react-redux";
import firebase from "firebase";
import { estudoDoDia } from "../actions/AutenticacaoActions";
export class estudoDia extends Component {
componentWillMount() {
//I've tried with 'this.props.quarta' and it didn't work
props.estudoDia(props.quarta);
}
render() {
return (
<View>
<Text>{props.quarta}</Text>
</View>
);
}
}
const mapStateToProps = state => ({
quarta: state.AutenticacaoReducer.quarta
});
export default connect(mapStateToProps, { estudoDoDia })(estudoDia);
types.js
export const MATERIA_DO_DIA = 'materia_do_dia';
ActionReducer.js. I import types and return payload
import { MATERIA_DO_DIA } from "../actions/types";
const INITIAL_STATE = {
quarta: "T.I Program"
};
export default (state = INITIAL_STATE, action) => {
console.log(action);
switch (action.type) {
case MATERIA_DO_DIA:
return { ...state, quarta: action.payload };
default:
return state;
}
};
AutenticacaoActions.js. Used snaphot
import firebase from "firebase";
import { Actions } from "react-native-router-flux";
import { MATERIA_DO_DIA } from "./types";
export const estudoDoDia = quarta => {
return dispatch => {
firebase.database
.ref("/DiasSemana/Quarta")
.once("value")
.then(snapshot => {
quarta = snapshot.val();
dispatch({
type: MATERIA_DO_DIA,
payload: snapshot.val
});
});
};
};
have image in link
enter image description here
thank you if you can help me
I thank you all for your help, in case I discovered that the problem is in the estudoDoDia method in AuthenticationActions.js, I made this change and it worked
export const estudoDoDia = (quarta) => {
return dispatch => {
firebase.database().ref('DiasSemana/Quarta').once('value', function (snapshot) {
console.log(snapshot.val())
quarta = snapshot.toJSON();
dispatch(
{
type: MATERIA_DO_DIA,
payload: quarta
})
})
}
}
Inside once I made it call a function passing the snapshop as a parameter and it worked.
I thank you for your help and thank you all

action does not modify state

I am trying to add user metadata to my store when mounting a screen. However, when I send the action to the reducer, the store is not modified.
I would expect props after sending the action to be as follows:
{addUserMetaData: ƒ addUserMetaData(user_object),
user: {firestore_doc: {name: "Joe"}}
}
What am i missing here?
To reproduce, react-native-init mwe then add the following code. I've added an image of the app logs below.
App.js
import React, { Component} from 'react';
import { View } from 'react-native';
import Screen from './src/screen';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
const userReducer = function userReducer(state = {}, action) {
console.log('action', action);
switch (action.type) {
case "ADD_USER_METADATA":
return { ...state, firestore_doc: action.payload };
default:
return { ...state };
}
};
const store = createStore(userReducer);
export default class App extends Component {
render() {
return (
<Provider store={store}>
<View>
<Screen />
</View>
</Provider>
);
}
};
src/screen.js
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { connect } from 'react-redux';
const addUserMetaData = (user) => ({
type: "ADD_USER_METADATA",
payload: user
})
class Screen extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
const user = { name: "Joe" };
console.log('props', this.props);
this.props.dispatch(addUserMetaData(user));
console.log('props after action', this.props);
}
render() {
return (
<View>
<Text>Welcome to react native</Text>
</View>
)
}
}
const mapStateToProps = state => {
return { user: state };
};
export default connect(mapStateToProps)(Screen);
Fixed https://snack.expo.io/#janithar/c3RhY2
Lines I changed
return { ...state, firestore_doc: action.payload };
Please added state.firestore_doc instead of state because in reducer action.payload assign the data in firestore_doc state so you are not getting data from state.user
const mapStateToProps = state => {
return { user: state.firestore_doc };
};

Resources