I'm new to react and react-native (and pretty much everything in general...), I'm trying to follow facebook's tutorial on state and props. I'm playing around with the code and I ran into some issues.
I've modified my Apps.js to look like this:
import React, { Component } from 'react';
import { Text, View, Image, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f1f',
alignItems: 'center',
justifyContent: 'center',
},
});
class Blink extends Component {
constructor(props) {
super(props);
this.state = {showText: true};
// Toggle the state every second
setInterval(() => {
this.setState(previousState => {
return { showText: !previousState.showText };
});
}, 1000);
}
render() {
let display = this.state.showText ? this.props.text1 : this.props.text2;
let pic = this.state.showText ? {uri: this.props.url1} : {uri: this.props.url2}
return (
<View>
<Image source={pic} style={{width: 193, height: 110}}/>
<Text>{display}</Text>
</View>
);
}
}
export default class BlinkApp extends Component {
render() {
return (
<View style={styles.container}>
<Blink text1='test1' />
<Blink text2='test2' />
<Blink url1='https://www.gizbot.com/img/2015/08/10-1439192289-lolemoji.jpg' />
<Blink url2='http://s3.india.com/wp-content/uploads/2015/08/haha-nelson-simpsons.jpg' />
</View>
);
}
}
Instead of blinking three lines of text like the one in the tutorial, it's suppose to blink two different images with two different lines of text (text1 and text2) using my own StyleSheet. The issue I'm running into is that they are not properly aligned. I can't get them to center no matter what I try.
The two different images it displays/blinks are here and here
What I want them to look like are here and here
So my questions are:
1) Does it matter where I define style? e.g. in my code, I've included them inside the second render, but I've noticed that if I put them inside the first render, different results occur. What is the difference?
2) Am I using props incorrectly here? What should I be doing instead to define the two images and texts as part of my props?
3) Are setInterval and previousState native react libraries? How are they being called? i.e. what's triggering setInterval to change the value of showText?
4) when is setState being called?
I rewrite your code, and I think it works as your expect now.
to your questions:
1&2: the way you use style and props is wrong, see my code below.
3: setInterval is native react libraries, you can find the usage in https://facebook.github.io/react-native/docs/timers.html
4: setState is called by your code, please look at the document https://facebook.github.io/react-native/docs/state.html
import React, { Component } from 'react';
import { Text, View, Image, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f1f',
alignItems: 'center',
justifyContent: 'center',
},
});
class Blink extends Component {
render() {
const { text, url } = this.props;
console.log('url' + url);
return (
<View>
<Image source={{uri:url, cache: 'force-cache'}} style={{width: 193, height: 110}}/>
<Text>{text}</Text>
</View>
);
}
}
export default class BlinkApp extends Component {
constructor(props) {
super(props);
this.state = {
showFirst: true,
};
}
componentDidMount() {
setInterval(() => {
this.setState({
showFirst: !this.state.showFirst
});
}, 1000);
}
render() {
const showFirst = this.state.showFirst;
return (
<View style={styles.container}>
{showFirst && <Blink url="https://www.gizbot.com/img/2015/08/10-1439192289-lolemoji.jpg" text='test1' />}
{!showFirst && <Blink url="http://s3.india.com/wp-content/uploads/2015/08/haha-nelson-simpsons.jpg" text='test2' />}
</View>
);
}
}
Related
I'm facing a problem there is a styled component named Breadcrumb but that component depends upon 1 separate styled-components i.e BreadcrumbItem. Both components have different props.
BreadcrumbItem.js:
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
const propTypes = {
/** Active the current BreadcrumbItem. */
active: PropTypes.bool,
/** Additional classes. */
className: PropTypes.string
};
const AbstractBreadcrumbItem = (props) => {
const { className, active, ...attributes } = props;
return <li {...attributes} className={className} />;
};
AbstractBreadcrumbItem.propTypes = propTypes;
const BreadcrumbItem = styled(AbstractBreadcrumbItem)``;
BreadcrumbItem.propTypes = propTypes;
export default BreadcrumbItem;
Breadcrumb.js:
import React from "react";
import styled from "styled-components";
import PropTypes from "prop-types";
const propTypes = {
/** Additional classes. */
className: PropTypes.string,
/** Primary content. */
children: PropTypes.node,
/** Custom separator */
separator: PropTypes.string,
/** Change the look and feel of the BreadcrumbItem. */
scheme: PropTypes.oneOf(["red", "purple"]).isRequired
};
const defaultProps = {
scheme: "red",
separator: "/"
};
const AbstractBreadcrumb = props => {
const { className, children, separator, scheme, ...attributes } = props;
return (
<ul {...attributes} className={className}>
{children}
</ul>
);
};
AbstractBreadcrumb.propTypes = propTypes;
AbstractBreadcrumb.defaultProps = defaultProps;
const Breadcrumb = styled(AbstractBreadcrumb)`
display: flex;
flex-wrap: wrap;
padding: 18px 26px;
margin-bottom: 1rem;
list-style: none;
background-color: #fbfbfb;
border-radius: 4px;
li + li:before {
content: "${props => props.separator}";
}
li + li {
padding-left: 8px;
}
li + li::before {
display: inline-block;
padding-right: 0.5rem;
}
li a {
font-size: 14px;
transition: color .4s linear;
color: ${props => (props.scheme === "red" ? "red" : "purple")};
&:hover {
color: black;
}
}
`;
Breadcrumb.propTypes = propTypes;
Breadcrumb.defaultProps = defaultProps;
export default Breadcrumb;
This is the main markup to create the Breadcrumb.
App.js:
import React from 'react';
import Breadcrumb from './Breadcrumb';
import BreadcrumbItem from './BreadcrumbItem';
export default function App() {
return (
<div className="App">
<Breadcrumb scheme="red">
<BreadcrumbItem>
Home
</BreadcrumbItem>
<BreadcrumbItem>
Shop
</BreadcrumbItem>
<BreadcrumbItem active>
Product
</BreadcrumbItem>
</Breadcrumb>
</div>
);
}
What problem I'm facing is I want to use the active prop of the BreadcrumbItem component inside the parent Breadcrumb component to change the look and feel of the item according to the scheme.
I found the first way which is to add the BreadcrumbItem styles inside the component itself and use something like this ${props => props.active ? css`` : css``}. But Is there a way in styled-component to access the child component prop inside the Parent component?
Please answer the question in the context of styled-components.
Live link: Codesandbox
I'd suggest to move the styling of list item, i.e. <li>, to its own component, i.e. BreadcrumbItem. In this scenario you won't need to access the state of child component instead you'll be handling active state in <li> styles. And it'll look more cleaner and separation of concern (which React recommends) will be there.
[EDIT]: Sample code to access props of children
const List = ({ children }) => {
return (
<ul>
{React.Children.map(children, x => {
console.log(x.props); // get props of children
return x;
})}
</ul>
);
};
const Item = ({ children }) => <li>{children}</li>;
export default function App() {
return (
<List>
<Item>Hello</Item>
<Item active>HI</Item>
</List>
);
}
I've been trying to follow the DynamicHeightTableColumn example and adapt it for my use case. I can see in the CellMeasurer demo that the single-line rows have the default height, defined when initializing the cache. However, in my case, it seems like single-line rows always have the tallest row height, stored in the cache, instead of the default one.
Here is my code:
import * as React from 'react';
import * as Immutable from 'immutable';
import { Table, Column, AutoSizer, CellMeasurer, CellMeasurerCache } from 'react-virtualized';
interface Props {
logs: Immutable.List<Immutable.Map<string, any>>;
columns: (
width: number
) => Array<{
name: string;
key: string;
width: number;
variableHeight?: boolean;
}>;
}
export default class LogTable extends React.Component<Props, {}> {
private cache: CellMeasurerCache;
constructor(props) {
super(props);
this.cache = new CellMeasurerCache({
defaultHeight: 20,
fixedWidth: true,
keyMapper: () => 1
});
}
render() {
const { logs } = this.props;
return (
<AutoSizer disableHeight>
{({ width }) => (
<Table
headerHeight={20}
height={250}
rowCount={logs.size}
rowHeight={this.cache.rowHeight}
width={width}
overscanRowCount={2}
rowRenderer={this.rowRenderer}
headerClassName='col-header'
gridClassName='log-table-grid'
rowClassName='log-table-row'
className='log-table'
rowGetter={({ index }) => logs.get(index)}
deferredMeasurementCache={this.cache}>
{this.renderColumns(width)}
</Table>
)}
</AutoSizer>
);
}
private renderColumns(width) {
return this.props.columns(width).map(({ name, key, width, variableHeight }, idx) => {
const props: any = {
label: name,
dataKey: key,
width,
key,
className: 'column'
};
if (variableHeight) {
props.cellRenderer = this.cellRenderer.bind(this, idx);
}
return <Column {...props} />;
});
}
private rowRenderer(params) {
const { key, className, columns, rowData, style } = params;
if (!rowData) {
return null;
}
return (
<div className={className} key={key} style={style}>
{columns}
</div>
);
}
private cellRenderer(colIndex, { dataKey, parent, rowIndex }) {
const content = this.props.logs.get(rowIndex).get(dataKey);
return (
<CellMeasurer
cache={this.cache}
columnIndex={colIndex}
key={dataKey}
parent={parent}
rowIndex={rowIndex}>
<div style={{ whiteSpace: 'normal' }} title={content}>
{content}
</div>
</CellMeasurer>
);
}
}
And this is the output (see 2nd row in the table that's too tall for its content)
The only styling (less) I have is the following, which I don't think can cause this behavior
.log-table {
font-size: 14px;
.col-header {
font-size: 15px;
text-align: center;
}
.log-table-grid {
outline: none;
font-family: monospace;
}
.log-table-row {
border-bottom: 1px solid gray;
padding: 3px;
}
}
So, I'm trying to create a custom Svgicon, but all the source code uses the paths directly. Is there anyway I can add an SVG icon from an image like this?
import { SvgIcon } from '#material-ui/core';
import React from 'react';
const iconStyles = {
marginRight: 24,
};
export const LawyersIcon = props => (
<SvgIcon {...props}>
<img src="https://pictures-for-website.nyc3.digitaloceanspaces.com/icons/team.svg" />
</SvgIcon>
);
So, you actually don't need to use SvgIcon at all, you can just create your own icon. This is my final code:
import { withStyles } from '#material-ui/core';
import React from 'react';
#withStyles(theme => ({
svg_icon: {
width: '1em',
height: '1em',
display: 'inline-block',
fontSize: '24px',
transition: 'fill 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms',
flexShrink: 0,
userSelect: 'none',
}
}))
export class LawyersIcon extends React.Component {
render() {
const { classes } = this.props
return <div className={classes.svg_icon}>
<img src="https://pictures-for-website.nyc3.digitaloceanspaces.com/icons/team.svg" />
</div>
}
}
Hopefully the script bellow will show roughly what I am trying to achieve.
But essentially, using a string stored in a state, be able to have a component holder dynamically load different components on change.
So you will see 2 component imported at the top (but ideally these could be a 100 different ones.
A currentSlide state that holds the string name of the component.
And a SlideLoader component that would ideally load imported components based on a string name.
Then the button's switch the component through resetting the state name.
Thank you!
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
} from 'react-native';
import SlideA from './slideA';
import SlideB from './slideB';
const styles = StyleSheet.create({
dummyContainer: {
flex: 0,
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
backgroundColor: '#999999',
},
buttonHolder: {
position: 'absolute',
top: 4,
left: 0,
},
button: {
height: 50,
width: 300,
backgroundColor: 'red',
marginBottom: 4,
textAlignVertical: 'center',
textAlign: 'center',
fontWeight: 'bold',
},
});
export default class Switcher extends Component {
constructor(props, context) {
super(props, context);
let state = {
currentSlide: 'SlideA',
}
}
render() {
// obvisously wrong part...
let SlideLoader = this.state.currentSlide;
// end of obvisously wrong part...
return (
<View
style={[
styles.dummyContainer,
]}
>
<SlideLoader />
<View
style={styles.buttonHolder}
>
<Text
onPress={() => {
console.log('SLID A');
setState({ currentSlide: 'SlideA' });
}}
style={[styles.button]}
>
Slide A
</Text>
<Text
onPress={() => {
console.log('SLID B');
setState({ currentSlide: 'SlideB' });
}}
style={[styles.button]}
>
Slide B
</Text>
</View>
</View>
);
}
}
ok here we go :
render() {
let SlideLoader;
if(this.state.currentSlide == 'SlideA')
SlideLoader=<SlideA />
else
SlideLoader=<SlideB />
return (
<View
style={[
styles.dummyContainer,
]}
>
{SlideLoader}
<View
style={styles.buttonHolder}
>
<Text
onPress={() => {
console.log('SLID A');
setState({ currentSlide: 'SlideA' });
}}
style={[styles.button]}
>
Slide A
</Text>
<Text
onPress={() => {
console.log('SLID B');
setState({ currentSlide: 'SlideB' });
}}
style={[styles.button]}
>
Slide B
</Text>
</View>
</View>
);
}
Cheers:)
I would like to ask, is there any solution to come out with something like Messenger(Mobile App) searching function? The route is having a basic view elements. When user is typing in some words, the search will start to function, within the same screen, another view overlap to show the filter list. I had tried to use react-native-overlap module but it not work well.
var React = require ('react-native');
var {
Text, View, StyleSheet, TextInput, Dimensions, Image, Platform, ScrollView, ReactNative, DeviceEventEmitter,TouchableOpacity
} = React;
var NavigationBar = require ('../Components/NavigationBar');
var SearchBarFromNodeModule = require ('react-native-search-bar');
var Overlay=require('react-native-overlay');
var Recent = React.createClass({
getInitialState(){
return {
isVisible:'aa',
};
},
onNameChanged(e){
//todo something here
// alert('asd');
},
render (){
return (
<View>
<View style={styles.navbarContainer}>
<SearchBarFromNodeModule ref='searchBar' placeholder='Search' showsCancelButton={true} onChange={this.onNameChanged} />
</View>
<View style={{flex:1, flexDirection:'column'}}>
<View style={{backgroundColor:'#F4FA58',flex:1,height:40}}/>
<View style={{backgroundColor:'#58FAF4',flex:1,height:40}}/>
<View style={{backgroundColor:'#F4FA58',flex:1,height:40}}/>
<View style={{backgroundColor:'#58FAF4',flex:1,height:40}}/>
<View style={{backgroundColor:'#F4FA58',flex:1,height:40}}/>
<View style={{backgroundColor:'#58FAF4',flex:1,height:40}}/>
</View>
</View>
);
},
});
var styles=StyleSheet.create({
navbarContainer: {
height: 65,
paddingTop: 20,
},
button:{
height:40,
textAlign:'center',
fontSize:18,
marginBottom:10,
marginTop:10,
color:'blue',
}`enter code here`
});
module.exports = Recent;
Now there is some color boxes after the search bar, when user is typing something, onChange function will take place. But I have no idea how to overlap the color boxes.
This gets the job mostly done. The only issue is the search results box renders under the text view below the search input. This could be corrected in a few ways but I personally would likely look to the zIndex feature introduced in 0.30 that is coming out soon.
https://rnplay.org/apps/CJNPWg
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TextInput
} from 'react-native';
class SearchResults extends React.Component {
render() {
if (this.props.search.toUpperCase() !== 'BAM') {
return null;
}
return (
<View style={styles.searchResults}>
<Text>
Do whatever your heart desires here... Might I recomend a list view??
</Text>
</View>
);
}
}
class SearchBox extends React.Component {
render() {
return (
<View>
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
value={this.props.search}
onChangeText={this.props.onChange}
placeholder="Try 'BAM'!"
/>
<SearchResults search={props.search} />
</View>
);
}
}
class SampleApp extends React.Component {
state = {
currentSearch: ''
};
onCurrentSearchChange(text) {
this.setState({
currentSearch: text
});
}
render() {
return (
<View style={styles.container}>
<Text>Enter your search</Text>
<SearchBox search={this.state.currentSearch} onChange={this.onCurrentSearchChange.bind(this)} />
<Text>Some text below the search box...</Text>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 30
},
searchResults: {
position: 'absolute',
backgroundColor: 'white',
borderColor: 'black',
borderWidth: 1
}
});
AppRegistry.registerComponent('SampleApp', () => SampleApp);