Array JSON with ListView in React-Native - json

I have an issue, I'm trying to make a little database offline inside a JSON, like this:
[
{
title: "Carros",
carros: [
{
nome: "Ferrari"
}
]
},
{
title: "Motos",
carros: [
{
nome: "Suzuki"
}
]
}
];
From now, my HomeScreen lists the categories as "Carros" and "Motos", but when I want to enter in subtopic like "carros", but I can't.
Currently using a ListView
{ list.map((item, i) => (
<View>
<TouchableOpacity
onPress={() =>
this.props.navigation.navigate("Listagem", {
itemName: item.title
})
}
>
<ListItem key={item.title} title={item.title} />
</TouchableOpacity>
</View>
))
}
How to get child items?

Carros -> carros
Motos -> carros ???
Motos -> motos
If you only have "carros", there are no "motos". Hope you get my point.

In order to get the carros Object inside the Listagem screen you need to pass it as an prop.
<TouchableOpacity
onPress={() =>
this.props.navigation.navigate("Listagem", {
itemName: item.title,
childItems: item.carros
})
}
>
In you Listagem screen you will get these properties.
constructor() {
super();
const { navigation } = this.props;
const itemName = navigation.getParam('itemName', 'defaultName');
const childItems = navigation.getParam('childItems', []);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(childItems),
};
}
render(){
return(
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => <Text>{rowData.nome}</Text>}
/>
)
}

You can do this in your home screen:
import React, { Component } from 'react';
import {FlatList, ScrollView} from 'react-native';
import { List, ListItem } from 'react-native-elements'; //this is not necessary. You may use it for aesthetic purposes only.
const cars = [
{
title: "Carros",
carros: [
{
nome: "Ferrari"
}
]
},
{
title: "Motos",
carros: [
{
nome: "Suzuki"
}
]
}
];
export default class Home extends Component {
renderCars() {
return (
<List
containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}
>
<FlatList
data={cars}
keyExtractor={item => item.title}
renderItem={({ item }) => (
<ListItem
titleStyle={yourstyles.title}
hideChevron
title={item.title}
onPress={() => this.props.navigation.navigate(
'ChildPage',
{
cars: item //pass the entire item as a prop. This way you will have all its subtopics in your child page
}
)}
/>
)}
/>
</List>
)
}
render() {
return (
<ScrollView>
{this.renderCars()}
</ScrollView>
)
}
}
In your child page where you want to list the subtopics of 'carros' for example. Remember you passed the entire item as a prop, so that prop will be available for you in the child page.
So now you can do this in your child page:
//ChildPage
import React, { Component } from 'react';
import {FlatList, ScrollView, View, Text} from 'react-native';
import { List, ListItem } from 'react-native-elements'; //this is not necessary. You may use it for aesthetic purposes only.
export default class ChildPage extends Component {
renderSubtopics() {
const { cars } = this.props.navigation.state.params; // remember the entire item you passed down from Home, we will use it here
return (
<List
containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}
>
<FlatList
data={cars.carros}
keyExtractor={item => item.nome}
renderItem={({ item }) => (
<ListItem
titleStyle={yourstyles.title}
hideChevron
title={item.nome}
onPress={() => //do whatever )}
/>
)}
/>
</List>
)
}
render() {
return (
<ScrollView>
<View>
<Text>
{this.props.navigation.state.params.cars.title}
<Text>
</View>
{this.renderSubtopics()}
</ScrollView>
)
}
}

Related

How i can do my component in React.js have a individual behavior?

I'm implementing a Like and Dislike Button, and I wanna that when I click them will be with other colors, but just the clicked component, when I click all buttons change the state, can anybody help me?
`
const indexPost = async () => {
const data = await api.get('/api/posts')
if(data.data.length !=0){
const dataArray = data.data
if(dataArray.length === 0) {
return
}else{
return(
setPost(dataArray.map( data => (
<Post key={data._id} id={data._id} title={data.title} text={data.text}>
<Like id={data._id}></Like>
</Post>
)))
)
}
}
}
export default function Like({itemId}) {
const context = useContext(notificationContext)
const {isLoved, Like, Loved, Unlike, isLike, isUnlike, setIsLike, setIsUnlike, setIsLoved } = context
return(
<div className={styles.likeContainer} key={itemId}>
{isLike ? (
<button className={styles.likeContent} onClick={() => setIsLike(false)}><Icon.ThumbsUp className={styles.Icon} fill="#5CB0BB" ></Icon.ThumbsUp></button>) :
(<button className={styles.likeContent} onClick={() => Like() }><Icon.ThumbsUp className={styles.Icon} ></Icon.ThumbsUp></button>)}
{isLoved ?
(<button className={styles.likeContent} onClick={() => setIsLoved(false)}><Icon.Heart className={styles.Icon} fill="red" ></Icon.Heart> </button>) :
(<button className={styles.likeContent} onClick={() => Loved() }><Icon.Heart className={styles.Icon} ></Icon.Heart></button>)}
{isUnlike ? (
<button className={styles.likeContent} onClick={() => setIsUnlike(false)}><Icon.ThumbsDown className={styles.Icon} fill="#702BA6" ></Icon.ThumbsDown> </button>) :
(<button className={styles.likeContent} onClick={() => Unlike()}><Icon.ThumbsDown className={styles.Icon} ></Icon.ThumbsDown></button>
)}
</div>
)
};
I have implemented the similar one in my project, it is very basic , it shows how to update the likes , you need to handle the cases of user authentication and stuff
App.js
import { useState, useEffect, createContext, useReducer } from "react";
import { updateArrayOfObj } from "./utils";
import AllPosts from "./AllPosts";
export const PostsContext = createContext();
const initialState = {
posts: [
{
_id: "1",
name: "Browny",
image: "http://placekitten.com/200/310",
likes: 0,
love: 0,
dislikes: 0
},
{
_id: "2",
name: "Blacky",
image: "http://placekitten.com/200/320",
likes: 0,
love: 0,
dislikes: 0
},
{
_id: "3",
name: "SnowWhite",
image: "http://placekitten.com/200/300",
likes: 0,
love: 0,
dislikes: 0
}
]
};
const reducer = (state, action) => {
switch (action.type) {
case "UPDATE_POST":
return {
...state,
posts: updateArrayOfObj(
state.posts,
action.payload.obj,
"_id",
action.payload._id
)
};
case "CREATE_POST":
return {
...state,
posts: [...state.posts, ...action.payload.data]
};
case "DELETE_POST":
return {
...state,
posts: state.posts.filter((ele) => ele._id !== action.payload._id)
};
default:
return state;
}
};
export default function App() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<PostsContext.Provider
value={{
state,
dispatch
}}
>
<div className="App">
<AllPosts />
</div>
</PostsContext.Provider>
);
}
PostsAll.js
import Post from "./Post";
import { PostsContext } from "./App";
import { useContext } from "react";
export default function AllPosts() {
const { state } = useContext(PostsContext);
return (
<div className="allPosts">
{state.posts.map((item) => {
return (
<Post
name={item.name}
image={item.image}
likes={item.likes}
love={item.love}
dislikes={item.dislikes}
id={item._id}
key={item._id}
/>
);
})}
</div>
);
}
Post.js
import { PostsContext } from "./App";
import { useContext } from "react";
export default function Post(props) {
const { state, dispatch } = useContext(PostsContext);
const handleUserInteraction = (type, id) => {
dispatch({
type: "UPDATE_POST",
payload: {
obj: { [type]: props[type] + 1 },
_id: id
}
});
};
return (
<div className="post">
<h3>{props.name}</h3>
<img src={props.image} alt="cat" />
<br />
<button onClick={() => handleUserInteraction("likes", props.id)}>
{props.likes} Like
</button>{" "}
<button onClick={() => handleUserInteraction("love", props.id)}>
{props.love} Love
</button>{" "}
<button onClick={() => handleUserInteraction("dislikes", props.id)}>
{props.dislikes} Dislike
</button>
</div>
);
}
You can refer to this codesandbox to implement the same
You can use onClick() on each like button and attach it with a function, then you can get the value of that particular like with e.currentTarget.id and change its css/style the way you want.
const handleClick=(e)=>
{
console.log(e.currentTarget.id);
}

Call function to update Context in React Native

I am having problems calling a function in React Native. I simply want to change the value of 'Context'. Here is some code, first the script for 'context':
//LogContext.js
import React, { useState } from 'react'
export const LogContext = React.createContext({
set: "en",
login: "false"
})
export const LogContextProvider = (props) => {
const setLog = (login) => {
setState({set: "jp", login: login})
}
const initState = {
set: "en",
login: "false"
}
const [state, setState] = useState(initState)
return (
<LogContext.Provider value={state}>
{props.children}
</LogContext.Provider>
)
}
and the 'app.js' code:
//app.js
import React, { useState, useContext } from 'react';
import { Button, Text, TextInput, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { LogContextProvider, LogContext } from './LogContext'
function HomeScreen({ navigation }) {
const state = useContext(LogContext);
return (
<>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Passed config: {JSON.stringify({state})}</Text>
<Text>Home Screen</Text>
</View>
{state.login === 'false' ? (
<Button
title="Go to Login"
onPress={() => navigation.navigate('Login')}
/>
) : (
<Button title="Stuff" onPress={() => navigation.navigate('DoStuff')} />
)}
</>
);
}
function LoginScreen({ navigation }) {
const state = useContext(LogContext);
//do stuff to login here...
state.setLog('true'); //not functional...
return (
<LogContext.Provider value={'true'}> //value={'true'} also not functional...
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Login Screen</Text>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
</View>
</LogContext.Provider>
);
}
function StuffScreen({ navigation }) {
//do other stuff here...
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="DoStuff" component={StuffScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
Obviously I am not too familiar with React Native. Any advice on how to call the "setLog()" function as to enable an update of the value for the 'Context' global variable would be greatly appreciated. I thank you in advance.
I am trying to modify my "App()" function to wrap the Navigator within the provider as suggested by another user...however this following is completely non-functional...suggestions appreciated:
const Stack = createStackNavigator();
function App() {
const [data, setData] = useState({
set: 'en',
login: 'false',
});
const state = { data, setData };
return (
<LogContext.Provider value={state}>
<NavigationContainer>
{state.data.login === 'true' ? (
<Stack.Navigator>
<Stack.Screen name="BroadCast" component={VideoScreen} />
<Stack.Screen name="Logout" component={LogoutScreen} />
</Stack.Navigator>
) : (
<Stack.Navigator>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
)}
</NavigationContainer>
</LogContext.Provider>
);
}
The issue you are having is not having a set function in your context and i dont see a need for a separate LogContext provider function.
You can simply do that part in your app.js or whatever the root function. The below example does that. You can see how a state value is passed along with a function to set the values and this can be modified from teh Login component which is inside the provider. If you use a separate provider its a bit confusing. The below is a working example without the navigation part to give you an idea.
const LogContext = createContext({
data: {
set: 'en',
login: 'false',
},
});
export default function App() {
const [data, setData] = useState({
set: 'en',
login: 'false',
});
const state = { data, setData };
return (
<LogContext.Provider value={state}>
<View style={{ flex: 1 }}>
<Text>{JSON.stringify(state.data)}</Text>
<Login />
</View>
</LogContext.Provider>
);
}
const Login = () => {
const state = React.useContext(LogContext);
return (
<View>
<Button
onPress={() => state.setData({ set: 'bb', login: 'true' })}
title="Update"
/>
</View>
);
};
To modify your code, you should wrap the main navigator inside the LogContext.Provider and maintain the state there which will help you do the rest.
Feel free to ask any further clarification :)

react native 2 dropdown depend on first one

I am trying to connect two dropdown with in react native,
same as country and city
if i select any country it should load cities from that country to second drop-down
all data is in a external json file
but nothing is loading in both drop down (picker)
json file :
{
"interest": [
{
"RAW_MATERIAL":["abc","cde"]
},
{
"OEM_PARTS":["xyz","qwer"]
},
{
"CONSUMABLES":["poiu","fjgl"]
},
{
"SERVICE":["xvcbv","qweiw"]
}
],
}
react native picker i use:
import React, { Component } from 'react';
import { Container,Picker,Button } from 'native-base';
const cData = require('../data.json');
export default class Vendorsupplies extends Component {
constructor(props) {
super(props);
this.state = {
interest:'',
interest2:''
};
}
interest(value: string) {
this.setState({
interest: value
});
}
interest2(value: string) {
this.setState({
interest2: value
});
}
<Picker
note
mode="dropdown"
style={{ width: 120 }}
selectedValue={this.state.interest}
onValueChange={this.interest.bind(this)}
name="intre"
>
{cData.interest.map((number) =>
<Picker.Item label={number.interest_in} value={number.interest_in} />
)}
</Picker>
<Picker
note
mode="dropdown"
style={{ width: 120 }}
selectedValue={this.state.intre2.interest}
onValueChange={this.intre2.interest.bind(this)}
name="intre2"
>
{cData.interest.map((number) =>
<Picker.Item label={number.intre2.interest_in} value={number.intre2.interest_in} />
)}
</Picker>
You can try it like that, I just done it with select but you will get the idea.
const cData = {
interest: [
{
RAW_MATERIAL: ['abc', 'cde'],
},
{
OEM_PARTS: ['xyz', 'qwer'],
},
{
CONSUMABLES: ['poiu', 'fjgl'],
},
{
SERVICE: ['xvcbv', 'qweiw'],
},
],
};
class TodoApp extends React.Component {
constructor(props) {
super(props);
this.state = {
interest: 'RAW_MATERIAL',
interest2: '',
};
}
renderOption() {
const el = cData.interest.find(
interest => Object.keys(interest)[0] === this.state.interest
);
if (el) {
return el[this.state.interest].map(option => (
<option value={option}>{option}</option>
));
}
return <option>empty</option>;
}
render() {
return (
<React.Fragment>
<select
value={this.state.interest}
onChange={e => {
e.persist();
this.setState(prev => ({
...prev,
interest: e.target.value,
}));
}}
>
{cData.interest.map(el => (
<option value={Object.keys(el)}>{Object.keys(el)}</option>
))}
</select>
<select
value={this.state.interest2}
onChange={e => {
e.persist();
this.setState(prev => ({ ...prev, interest2: e.target.value }));
}}
>
{this.renderOption()}
</select>
</React.Fragment>
);
}
}
ReactDOM.render(<TodoApp />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

How to call image from JSON that has local path in React Native

import React, { Component } from 'react';
import {
ScrollView,
StyleSheet,
} from 'react-native';
import axios from 'axios';
import CarDetail from '../components/CarDetail';
class CarList extends Component {
state = { cars: [] };
componentDidMount() {
axios.get('https://www.website.com/ajx/home_ajx/lister')
.then(response => this.setState({ cars: response.data.data[0]['S1']
}));
//Add an if statement here to notify the user when the request fails
}
renderCars() {
return this.state.cars.map(model =>
<CarDetail key={model.title} modelprop={model} />
);
}
render() {
console.log(this.state);
return (
<ScrollView>
{this.renderCars()}
</ScrollView>
);
}
}
export default CarList;
And the image path in the JSON file is as below:
"image": "data/models/peugeot-2008-138twf_600X400_.jpg",
Below is where I'm calling the image in another component
const CarDetail = ({ modelprop }) => {
const { image } = modelprop;
return (
<Card>
<CardSection>
<View>
<Image style={imageStyle}
source={{ uri: props.modelprop.image }}
/>
</View>
I believe I need to use some kind of prefix maybe in my Global.js which I couldn't find or figure out.
Any help is highly appreciated.
Mostly like your code has a bug:
const CarDetail = ({ modelprop }) => {
const { image } = modelprop;
return (
<View>
<Image
style={imageStyle}
source={{ uri: image }}
/>
</View>
);
}
If the image is something like data/models/peugeot-2008-138twf_600X400_.jpg, you should use `${Global.imageUrlPrefix}${image}` to concat all.

react-native-tab-navigator and redux performance issue

I hooked up the react-native-tab-navigator to a redux reducer using react-native-navigation-redux-helpers. When I press on a tab, the reducer changes the current tab state inside of the redux store. However, there is a lag between when I tap on a tab and when the tab is "selected" and renders the component. Is there any way to speed up the process of selecting a tab and rendering the view?
Here is my ApplicationTabs component:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { actions as navigationActions } from 'react-native-navigation-redux-helpers';
import { Tabs, Tab, Icon } from 'react-native-elements';
import Feed from '../feed';
import Inbox from '../inbox';
import { openDrawer } from '../../actions/drawer';
import styles from './styles.js';
const { jumpTo } = navigationActions;
class ApplicationTabs extends Component {
constructor(props) {
super(props)
}
_openDrawer() {
this.props.openDrawer();
}
_renderTabContent(tab) {
switch (tab.key) {
case 'feed':
return <Feed />;
case 'request':
return <Inbox />
default:
return <Feed />;
}
}
_changeTab (tab) {
const { tabs } = this.props;
this.props.jumpTo(tab.key, tabs.key)
}
render() {
const { tabs, drawerState } = this.props;
const children = tabs.routes.map((tab, i) => {
return (
<Tab
selected={tabs.index === i}
title={tab.title}
renderIcon={() => <Icon containerStyle={styles.iconContainer} iconStyle={styles.iconStyle} type='Entypo' name={tab.iconName} size={33} />}
onPress={() => this._changeTab(tab)}
titleStyle={styles.titleStyle}>
{this._renderTabContent(tab)}
</Tab>
)
});
return (
<Tabs tabBarStyle={styles.tabBarStyle}>
<Tab
selected={drawerState === 'opened'}
title='Menu'
renderIcon={() => <Icon containerStyle={styles.iconContainer} iconStyle={styles.iconStyle} type='Entypo' name='menu' size={33} />}
onPress={() => this._openDrawer()}
titleStyle={styles.titleStyle}>{this._renderTabContent(tabs.key)}</Tab>
{children}
</Tabs>
);
}
}
function mapDispatchToProps(dispatch) {
return {
jumpTo: (keyOrIndex, key) => dispatch(jumpTo(keyOrIndex, key)),
openDrawer: () => dispatch(openDrawer()),
};
}
function mapStateToProps(state) {
return {
tabs: state.tabs,
drawerState: state.drawer.drawerState
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ApplicationTabs);
Here is the tabReducer:
import { tabReducer } from 'react-native-navigation-redux-helpers';
const tabs = {
routes: [
{ key: 'feed', title: 'Feed', iconName:'home'},
{ key: 'request', title: 'Request', iconName: 'camera-alt' },
{ key: 'memoryBox', title: 'Memory Box', iconName: 'photo' },
{ key: 'search', title: 'Search', iconName: 'search' }
],
key: 'ApplicationTabs',
index: 0
};
export default tabReducer(tabs);