Building a Tic-Tac-Toe Game in React Native adding Styles - react-native

I am building a tic-tac-toe game and need to know how I can add an individual style to an individual board piece. If I am using state, would I need a variable that represents each piece on the board? Is there more of an elegant way of doing this. I posted my code here, just give you an idea on how it looks.
import React, { Component } from 'react';
import { ListView, StyleSheet, Text, View, TouchableOpacity } from 'react-native';
class MainApp extends Component {
state = {
clicked: true,
spacePlayed: [],
tables: [0, 1, 2, 3, 4, 5, 6, 7, 8],
playedSpace: [],
}
searchBoard = (index) => {}
_setBoard = (tableId) => {
this.setState({
clicked: !this.state.clicked,
});
var spacePlayed = this.state.playedSpace.push(tableId);
this.setState({ spacePlayed });
}
buildBoard = () => {
var clicked = false;
return (this.state.tables.map((table, index) => {
if (index === 0) {
return (
<TouchableOpacity key={index} onPress={() => this._setBoard(index)}>
<View style={styles.table}></View>
</TouchableOpacity>
);
} else {
return (
<TouchableOpacity key={index} onPress={() => this._setBoard(index)}>
<View style={styles.tableActive}></View>
</TouchableOpacity>
);
}
}));
}
render() {
const active = this.state.clicked
? styles.active
: null;
return (
<View style={styles.container}>
{this.buildBoard()}
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flexWrap: 'wrap',
flexDirection: 'row',
width: 200,
justifyContent: 'center',
alignItems: 'center',
marginLeft: 70,
marginTop: 20,
},
table: {
height: 50,
width: 50,
backgroundColor: '#78BEC5',
margin: 5,
justifyContent: 'center',
alignItems: 'center',
},
active: {
backgroundColor: '#ECAF4F',
},
tableActive: {
height: 50,
width: 50,
backgroundColor: '#ECAF4F',
margin: 5,
justifyContent: 'center',
alignItems: 'center',
},
});
export default MainApp;

Related

Cannot display the second product after i clicked first one in React native app

I'm trying to develop an app with React Native.
When I clicked on any product, I can see the product detail page correctly. But for the second click, the same product always appears as keep in a cache or something.
What am I missing out?
Maybe it is a state problem but I cannot figure it out.
Product Listing Page:
import { NavigationHelpersContext } from "#react-navigation/core";
import React, { Component } from "react";
import {
SafeAreaView,
ScrollView,
StatusBar,
View,
StyleSheet,
FlatList,
Text,
Image,
TouchableOpacity,
Alert,
useColorScheme,
} from "react-native";
import { getData } from "./loadData";
export default class Pekmez extends Component {
constructor(props) {
super(props);
this.state = {
refreshFlag: (Boolean = false),
data: [],
};
}
componentDidMount() {
this._unsubscribe = this.props.navigation.addListener("focus", () => {
const { route, navigation } = this.props;
const { params } = route;
console.log("_KAT fetch params:", params);
let suffix = "Product/" + params.id;
console.log("_KAT product:", suffix);
getData(suffix, "GET").then((val) => {
this.setState({ data: val.data }, () => {
console.log("state=>", this.state);
});
});
});
//id gelecek
//fetch
}
clickEventListener(item) {
this.props.navigation.navigate("UrunDetay", { ...item });
}
render() {
return (
<View style={styles.container}>
<View style={styles.headerbar}>
<Text style={styles.pagetitle}>Ürünler</Text>
</View>
<FlatList
style={styles.list}
contentContainerStyle={styles.listContainer}
data={this.state.data}
horizontal={false}
numColumns={2}
keyExtractor={(item) => {
return item.id;
}}
renderItem={({ item }) => {
return (
<TouchableOpacity
style={styles.card}
onPress={() => {
this.clickEventListener(item);
}}
>
<View style={styles.cardFooter}></View>
<Image
style={styles.cardImage}
source={{
uri:
"https://www.toptankoyurunleri.com/Uploads/Products/" +
item.id +
"/" +
item.filename,
}}
/>
<View style={styles.cardHeader}>
<View
style={{ alignItems: "center", justifyContent: "center" }}
>
<Text style={styles.title}>{item.title}</Text>
</View>
</View>
</TouchableOpacity>
);
}}
/>
</View>
);
}
}
const styles = StyleSheet.create({
headerbar: {
height: 55,
backgroundColor: "#f27a1a",
alignItems: "center",
justifyContent: "center",
paddingVertical: 15,
marginBottom: 10,
},
pagetitle: {
fontSize: 18,
flex: 1,
alignSelf: "center",
color: "#fff",
fontWeight: "bold",
},
container: {
flex: 1,
marginTop: 0,
},
list: {
paddingHorizontal: 5,
},
listContainer: {
alignItems: "center",
},
/******** card **************/
card: {
shadowColor: "#00000021",
shadowOffset: {
width: 0,
height: 6,
},
shadowOpacity: 0.37,
shadowRadius: 7.49,
elevation: 12,
marginVertical: 10,
backgroundColor: "white",
flexBasis: "42%",
marginHorizontal: 10,
},
cardHeader: {
paddingVertical: 10,
paddingHorizontal: 5,
borderTopLeftRadius: 1,
borderTopRightRadius: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
},
cardContent: {
paddingVertical: 5,
paddingHorizontal: 6,
},
cardFooter: {
flexDirection: "row",
justifyContent: "space-between",
paddingTop: 5,
paddingBottom: 5,
paddingHorizontal: 10,
borderBottomLeftRadius: 1,
borderBottomRightRadius: 1,
},
cardImage: {
height: 150,
width: 150,
alignSelf: "center",
},
title: {
fontSize: 13,
flex: 1,
alignSelf: "center",
color: "#696969",
fontWeight: "bold",
},
});
Product Detail Page
import React, { Component } from "react";
import {
SafeAreaView,
TouchableOpacity,
ScrollView,
StatusBar,
View,
StyleSheet,
Text,
Image,
useColorScheme,
Button,
BackHandler,
} from "react-native";
import {
Colors,
DebugInstructions,
Header,
LearnMoreLinks,
ReloadInstructions,
} from "react-native/Libraries/NewAppScreen";
import { WebView } from "react-native-webview";
export default class UrunDetay extends Component {
constructor(props) {
super(props);
this.state = {
detailData: {},
};
}
componentDidMount() {
console.log("this props detail:", JSON.stringify(this.props));
const { route, navigation } = this.props;
const { params } = route;
console.log("params:", params);
this.setState({ detailData: params });
}
render() {
const { detailData } = this.state;
console.log("deail:", this.props.navigation);
let vw = <Text>Loading...</Text>;
if (detailData.id && detailData.id > 0) {
vw = (
<View style={styles.container}>
<View style={styles.headerbar}>
<Text style={styles.pagetitle}>{this.state.detailData.title}</Text>
</View>
<WebView
source={{
uri:
"https://app.toptankoyurunleri.com/urun/urunadi/" +
this.state.detailData.id,
forceReload: this.state.forceReload,
}}
style={{ marginTop: 55 }}
/>
</View>
);
}
return vw;
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
headerbar: {
height: 55,
backgroundColor: "#fff",
flex: 1,
position: "absolute",
top: 0,
width: "100%",
paddingBottom: 15,
paddingTop: 15,
},
pagetitle: {
fontSize: 18,
flex: 1,
alignSelf: "center",
color: "#000",
fontWeight: "bold",
},
});
Where did you map your item in your list ? It appear to keep the same item or item.id in your state can you make test with breakpoints on your browser tool ?

im trying to add on press highlight the selected item in the flatlist using the keyExtractor

import React, {useState} from 'react';
import {Image, FlatList, Dimensions, StyleSheet} from 'react-native';
import FastImage from 'react-native-fast-image'
const picsumImages = new Array(28).fill("http://placeimg.com/640/360/any");
let generateRandomNum = () => Math.floor(Math.random() * 1001);
function renderItem({ item }) {
return (
<FastImage
source={{ uri: item}}
style={styles.itemView}
/>
);
}
const OtasView = (props) => {
const [images, setImages] = useState(picsumImages);
return (
<FlatList data={images} renderItem={renderItem} numColumns={3} style={{ marginLeft: 18, marginRight: 18, marginTop: 40 }} keyboardShouldPersistTaps="always"
showsVerticalScrollIndicator={false} keyExtractor={(renderItem) => generateRandomNum().toString()}/>
);
};
const styles = StyleSheet.create({
screen: {
flex: 1,
padding: 10,
alignItems: "center",
},
itemView: {
flex: 1 / 3,
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
margin: 5,
aspectRatio: 1,
borderRadius: 200 / 2
},
});
export default OtasView;
This might help
const [images, setImages] = useState(picsumImages);
onSelect = index => {
const data = […images].map(item => item.selected = false);
data[index].selected = true;
setImages(data);
}
function renderItem({ item, index }) {
const style = index.selected ? styles.profileImgContainer : {};
return (
<TouchableHighlight style={style} onPress={() => onSelect(index)}>
<FastImage
source={{ uri: item}}
style={styles.itemView}
/>
</TouchableHighlight>
);
export default styles = StyleSheet.create({
profileImgContainer: {
marginLeft: 8,
height: 80,
width: 80,
borderRadius: 40,
},
itemView: {
flex: 1 / 3,
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
margin: 5,
aspectRatio: 1,
borderRadius: 200 / 2
}
});

How to update/ refresh the expandable list view in react native

I am developing an android app using react native which includes a cart page. I have used [ExpandableListView]:https://aboutreact.com/expandable-list-view/) to show the items grouped under categories. Each Item has a '+' and '-' button to change the count. Here is my code:
DetailScreen.js:
import React, { Component } from 'react';
import { LayoutAnimation, StyleSheet, TouchableOpacity, View, Text, ScrollView, UIManager, Platform, TextInput, KeyboardAvoidingView, ImageBackground, Picker, Image, Linking, Alert, } from 'react-native';
export default class DetailsScreen extends Component
{
static navigationOptions = {
title: 'Details',
header: null,
}
constructor(props)
{
super(props);
if (Platform.OS === 'android') {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
this.state =
{
listDataSource: [
{
isExpanded: false,
category_name: 'Item 1',
subcategory: [{ id: 1, val: 'Sub Cat 1', count:'0' }, { id: 3, val: 'Sub Cat 3', count:'0' }],
},
{
isExpanded: false,
category_name: 'Item 2',
subcategory: [{ id: 4, val: 'Sub Cat 4', count:'0' }, { id: 5, val: 'Sub Cat 5', count:'0' }],
}],
};
}
updateLayout = index => {
LayoutAnimation.configureNext
(LayoutAnimation.Presets.easeInEaseOut);
const array = [...this.state.listDataSource];
array[index]['isExpanded'] = !array[index]['isExpanded'];
this.setState(() => {
return {
listDataSource: array,
};
});
};
updateSalonData = newData =>
{
console.log('new Data: ' + JSON.stringify(newData));
var tempData = [...this.state.listDataSource];
let index = tempData.findIndex(x => x.category_name === newData.category_name);
tempData[index] = newData;
this.setState(() => {
return {
listDataSource: tempData,
};
});
};
render() {
return (
<View style={{ marginStart: 10, marginEnd: 10, marginTop: 5, borderBottomWidth: 0.5 }}></View>
<Text style={styles.topHeading}>Services</Text>
<ScrollView enabled keyboardShouldPersistTaps={'handled'} showsVerticalScrollIndicator={false} contentContainerStyle={{ flexGrow: 1, }}>
{this.state.listDataSource.map((item, key) => (
<ExpandableItemComponent
key={item.category_name}
onClickFunction={this.updateLayout.bind(this, key)}
item={item}
updateSalonData = {this.updateSalonData.bind(this, item)}/>
))}
</ScrollView>
</View>
);
}
}
ExpandableItemComponent.js:
import React, { Component } from 'react';
import { LayoutAnimation, StyleSheet, View, Text, ScrollView, UIManager, TouchableOpacity, Platform, } from 'react-native';
export default class ExpandableItemComponent extends Component {
//Custom Component for the Expandable List
constructor(props) {
super(props);
console.log('props: ' + JSON.stringify(props.item));
this.state = {
layoutHeight: 0,
dataSource:props.item,
};
}
componentWillReceiveProps(nextProps) {
console.log('componentWillReceiveProps');
if (nextProps.item.isExpanded) {
this.setState(() => {
return {
layoutHeight: null,
};
});
} else {
this.setState(() => {
return {
layoutHeight: 0,
};
});
}
console.log('next Item: ' + JSON.stringify(nextProps.item) + "\n");
this.setState(() => {
return {
dataSource: nextProps.item,
};
});
}
shouldComponentUpdate(nextProps, nextState) {
if (this.state.layoutHeight !== nextState.layoutHeight) {
return true;
}
return false;
}
setItemCount = (id) =>
{
const tempItem = this.props.item;
const data = this.props.item.subcategory;
const index = data.findIndex(x => x.id === id);
// console.log('pricing Index: ' + index);
if (index !== -1) {
data[index]["cartCount"] = 10;
tempItem.subcategory = data;
this.props.updateSalonData(tempItem);
}
}
render() {
return (
<View>
{/*Header of the Expandable List Item*/}
<TouchableOpacity
activeOpacity={0.8}
onPress={this.props.onClickFunction}
style={styles.header}>
<Text style={styles.headerText}>{this.state.dataSource.category_name}</Text>
</TouchableOpacity>
<View
style={{
height: this.state.layoutHeight,
overflow: 'hidden',
}}>
{/*Content under the header of the Expandable List Item*/}
{this.state.dataSource.subcategory.map((item, key) => (
<TouchableOpacity
key={key}
style={styles.content}
onPress={() => alert('Id: ' + item.id + ' val: ' + item.val)}>
<View style={{ flex: 1, flexDirection: 'row', alignContent: 'center', justifyContent: 'space-between'}}>
<Text style={styles.text}>{item.val}</Text>
<View style={{ flexDirection: 'row', alignSelf: 'center', }}>
<Text style={styles.text}>{item.val}</Text>
<View style={{ height: 25, width: 75, flexDirection: 'row', borderRadius: 15, borderWidth: 1, alignSelf: 'center', justifyContent: 'space-evenly', borderColor: 'orange', overflow: 'hidden' }}>
<View style={{ alignContent: 'center', justifyContent: 'center' }}>
<Text onPress={()=>{this.setItemCount(item.id)}} style={{ width: 25, height: 25, fontSize: 12, color: 'orange', fontWeight: 'bold', textAlign: 'center', textAlignVertical: 'center' }}>+</Text>
</View>
<View style={{ borderWidth: 1, borderColor: 'orange', backgroundColor: 'orange', alignContent: 'center', justifyContent: 'center' }}>
<Text style={{ width: 25, height: 25, fontSize: 12, color: 'white', fontWeight: 'bold', textAlign: 'center', textAlignVertical: 'center' }}>{item.cartCount}</Text>
</View>
<View style={{ alignContent: 'center', justifyContent: 'center' }}>
<Text style={{ width: 25, height: 25, fontSize: 12, color: 'orange', fontWeight: 'bold', textAlign: 'center', textAlignVertical: 'center' }}>-</Text>
</View>
</View>
</View>
</View>
{/* <View style={styles.separator} /> */}
</TouchableOpacity>
))}
</View>
<View style={styles.separator} />
</View>
);
}
}
Now the problem is, When i click '+' button the count is actually incremented in the code but its not been updated in the UI. But when I collapse and expand the same item, now the value is updated. Someone Pls guide me to update the count once I click the + button.
Can you replace your this.state.dataSource to direct this.props.updateSalonData on ExpandableItemComponent.js
If an update was done in the parent class it will automatically update in child class if so do.
eg:
...
{this.props.updateSalonData.subcategory.map((item, key) => (
....
like this.

Change color after click on TouchableHighlight in react native

I have done a many research on the color change after press/click. Finally
I got this script for change the state and put it in the TouchableHighlight. But When i clicked on that, only the "underlayColor={'gray'}" is working. Can i get some idea ?
here is my code
import React, { Component } from 'react';
import {
StyleSheet,
Text,
StatusBar ,
TouchableOpacity,
View,
FlatList,
ActivityIndicator,
TouchableHighlight,
PropTypes,
Image,
Alert
} from 'react-native';
import Logo from '../components/Logo';
import Form from '../components/Front';
import {Actions} from 'react-native-router-flux';
export default class Login extends Component<{}> {
constructor() {
super();
this.state = {
dataSource: {},
pressed: false
};
}
izijackpotconfirm() {
Actions.izijackpotconfirm()
}
componentDidMount() {
var that = this;
let items = Array.apply(null, Array(25)).map((v, i) => {
return { id: i+1 };
});
that.setState({
dataSource: items,
});
}
static navigationOptions = {
title: "Izi Jackpot",
headerStyle: {
backgroundColor: "#354247"
},
headerTintColor: "#fff",
headerTitleStyle: {
fontWeight: "bold"
}
};
render() {
var jackpotNumbers = [];
let btn_class = this.state.black ? "NormalSet" : "SelectedSet";
return(
<View style={styles.container}>
<View style={styles.middlecontainer}>
<Text style={styles.logoText}>Please Select 5 Numbers and Submit</Text>
</View>
<FlatList
data={this.state.dataSource}
renderItem={({ item }) => (
<View style={{ flex: 1, flexDirection: 'column', margin: 1 }}>
<TouchableHighlight
onPress={() => { Alert.alert(this.state.pressed) }}
style={[
styles.iziPizi,
this.state.pressed ? { backgroundColor: "blue" } : {}
]}
onHideUnderlay={() => {
this.setState({ pressed: false });
}}
onShowUnderlay={() => {
this.setState({ pressed: true });
}}
underlayColor={'gray'}
>
<Text style={styles.buttonText}>{ item.id}</Text></TouchableHighlight>
</View>
)}
//Setting the number of column
numColumns={5}
keyExtractor={(item, index) => index}
/>
<View style={styles.middlecontainer}>
<TouchableOpacity style={styles.button} onPress={this.izijackpotconfirm} >
<Text style={styles.buttonText}>Submit</Text>
</TouchableOpacity>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container : {
backgroundColor:'#6F9000',
justifyContent: 'center',
flex: 1,
paddingTop: 30,
},
middlecontainer: {
textAlign: 'center',
alignItems: 'center',
justifyContent :'center',
flex:1
},
signupTextCont : {
flexGrow: 1,
alignItems:'flex-end',
justifyContent :'center',
paddingVertical:16,
flexDirection:'row'
},
signupText: {
color:'rgba(255,255,255,0.6)',
fontSize:16
},
signupButton: {
color:'#ffffff',
fontSize:16,
fontWeight:'500'
},
iziPizi: {
width: 55,
padding: 15,
margin: 5,
borderRadius: 80,
borderWidth: 2,
borderColor: '#FFFFFF',
flex:1
},
iziPiziPress: {
width: 55,
padding: 15,
margin: 5,
backgroundColor:'#1c313a',
borderRadius: 80,
borderWidth: 2,
borderColor: '#FFFFFF',
flex:1
},
button: {
width:300,
backgroundColor:'#1c313a',
borderRadius: 25,
marginVertical: 10,
paddingVertical: 13
},
buttonText: {
fontSize:16,
fontWeight:'500',
color:'#ffffff',
textAlign:'center'
},
logoText : {
color:'#FFFFFF',
fontSize: 16,
fontWeight: '500',
alignItems: 'center',
justifyContent:'center',
},
imageThumbnail: {
justifyContent: 'center',
alignItems: 'center',
height: 100,
},
});
One more thing to say that, i have used FlatList here. Please help on this. Thanks in advance.
The problem is in how you work with the styles inside the Touchable. My advice is to create 2 styles that contain the changes:
style={
this.state.pressed ? styles.pressed : styles.iziPizi
}
Inside the touchable of course:
<TouchableHighlight
onPress={() => { Alert.alert(this.state.pressed) }}
style={
this.state.pressed ? styles.pressed : styles.iziPizi
}
onHideUnderlay={() => {
this.setState({ pressed: false });
}}
onShowUnderlay={() => {
this.setState({ pressed: true });
}}
underlayColor={'gray'}
>
yes. there was a problem in FlatList. but i dont know what is its problem.
use ListItem of native-base instead.
remember that if you want to use ListItem, in constructor change
this.state = {
dataSource: {},
...
}
to
this.state = {
dataSource: [],
}
use array insead. here is a sample code for you.
<View style={{ flex: 1, flexDirection: 'column', margin: 1 }}>
<List>
{this.state.dataSource.map( item =>
<ListItem>
<TouchableHighlight
onPress={() => {}}
onShowUnderlay={this.onPress.bind(this)}
>
<Text style={styles.buttonText}>{ item.id}</Text>
</TouchableHighlight>
</ListItem> )
}
</List>
</View>
Also define onPress method.
another problem in your code is this that you setState of pressed.
it results that all of your element style will be changed. so all of your button backgroundColor will be changed.
so you must define pressed flag for every element in your array and change this flag

in styles not working value of State in the ternary operator

please tell me why the ternary operator does not take the value from state in StyleSheet
in input styles, the ternary operator does not understand the value from the state
at textinput focus, the value of the state becomes true, when changing, I want to change the styles, how else can this be realized
import React, { Component } from 'react';
import { TextInput,
View,
StyleSheet,
FlatList,
Text,
TouchableOpacity
} from 'react-native';
import Icon from 'react-native-vector-icons/Feather';
export default class Chat extends Component {
constructor() {
super();
this.state = {
items: [],
text: '',
sendButtonVisible: false
};
}
sendMessage = () => {
let message = this.state.text;
if (message != '') {
this.state.items.push({
key: message,
dateTime: this.dateTime()
});
this.setState({
items: [...this.state.items],
text: ''
});
}
}
dateTime = () => {
let date = new Date();
addZero = (num) => {
if(num >= 0 && num < 10) {
return `0${num}`;
}
return num;
}
let dateTime = `${addZero(date.getHours())}:${addZero(date.getMinutes())}`;
return(dateTime);
}
sendButtonVisible = () => {
if (this.state.sendButtonVisible) {
return(
<TouchableOpacity style={styles.sendButton} onPress={this.sendMessage}>
<Icon name='send' color='rgb(255, 255, 255)' size={25} />
</TouchableOpacity>
);
}
}
render() {
return (
<View style={styles.container}>
<View style={styles.flatListBox}>
<FlatList
data={this.state.items}
renderItem={({item}) =>
<View style={styles.messageBlock}>
<Text style={styles.message}>
{item.key}
<Text style={{fontSize: 10}}>{item.dateTime}</Text>
</Text>
</View>
}
/>
</View>
<View style={styles.inputBox}>
<TextInput
style={styles.input}
value={this.state.text}
onChangeText={(text) => this.setState({text})}
onFocus={() => this.setState({sendButtonVisible: true})}
onBlur={() => this.setState({sendButtonVisible: false})}
placeholder='Write a message'
/>
{this.sendButtonVisible()}
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-end',
backgroundColor: 'rgb(255, 255, 255)'
},
inputBox: {
flexDirection: 'row',
margin: 10
},
input: {
flex: 6,
borderColor: 'rgb(227, 227, 227)',
backgroundColor: 'rgb(227, 227, 227)',
borderWidth: 1,
borderRadius: 10,
//borderTopRightRadius: (this.state.sendButtonVisible) ? 0 : 10,
//borderBottomRightRadius: (this.state.sendButtonVisible) ? 0 : 10,
fontSize: 16,
paddingLeft: 15
},
sendButton: {
flex: 1,
backgroundColor: 'rgb(0, 206, 209)',
justifyContent: 'center',
alignItems: 'center',
borderTopRightRadius: 10,
borderBottomRightRadius: 10
},
flatListBox: {
flex: 1,
alignItems: 'flex-end',
margin: 10
},
messageBlock: {
flexDirection: 'row',
justifyContent: 'flex-end',
marginTop: 2,
},
message: {
fontSize: 16,
backgroundColor: 'rgb(0, 206, 209)',
paddingHorizontal: 10,
paddingBottom: 6,
paddingTop: 4,
borderRadius: 15,
color: '#fff'
}
});
enter image description here
bro this points to the current class and you are writing the styles const out of the class scope that's the reason it cannot find this.state.sendButtonVisible
you can only use this in the scope of the class. If you want to use it then move it inside the class