I have the following React Native picker component that works -
file name: dynamic-picker.js
import React, { Component } from "react";
import { Container, Content, Picker } from "native-base";
export default class DynamicPicker extends Component {
constructor(props) {
super(props);
this.state = {
selected: this.props.selected
}
}
onValueChange(value) {
this.setState({
selected: value
});
}
itemsList = () => {
return (this.props.items.map( (item, index) => {
return (<Picker.Item label={item} key={index} value={item} />)
}));
}
render() {
return (
<Container>
<Content>
<Picker
mode="dropdown"
selectedValue={this.state.selected}
onValueChange={this.onValueChange.bind(this)}
>
{ this.itemsList() }
</Picker>
</Content>
</Container>
);
}
}
It is being called by a Vue JS file as follows -
file name: distance.vue
<template>
<dynamic-picker :items="items" :selected="selected" ></dynamic-picker>
</template>
<script>
import DynamicPicker from './dynamic-picker';
export default {
components: {
DynamicPicker
},
data() {
return {
selected: 'yards',
items: ["yards", "feet", "meters"]
}
}
}
</script>
The picker component is being displayed correctly. When the user selects a different option, that change is displayed in the picker component. However, I am stuck on how to get the selected property in the distance.vue file to update when the user selects a different option. That value needs to be captured so it can be passed on to the caller of the distance.vue file and used for a calculation.
Figured it out - added a callback to props so the child can call that function to pass data back to the parent when the value is changed.
Here is the updated distance.vue file (parent) -
<template>
<dynamic-picker :items="items" :selected="selected" :onValueChange="onValueChange" ></dynamic-picker>
</template>
<script>
import DynamicPicker from './dynamic-picker';
export default {
components: {
DynamicPicker
},
data() {
return {
selected: 'yards',
items: ["yards", "feet", "meters"]
}
},
methods: {
onValueChange(value) {
this.selected = value;
}
}
}
</script>
Then in dynamic-picker.js (child) the only change necessary was here -
onValueChange(value) {
this.setState({
selected: value
});
this.props.onValueChange(value); // added this line
}
Related
I want to perform something equivalent to this:
export default class LoadingScreen extends React.Component {
componentDidMount() {
firebase.auth().onAuthStateChanged(user => {
this.props.navigation.navigate(user ? 'App' : 'Auth');
});
}
render() {
return (
<View style={styles.container}>
<Text>Loading</Text>
<ActivityIndicator size='large'></ActivityIndicator>
</View>
);
}
}
I have setup my routes to go through the Loading to check the user's auth state before proceeding to either Auth or App. When I add mounted(), the loading text and activity-indicator don't show.
<template>
<view class="container">
<nb-text>Loading</nb-text>
<activity-indicator size="large" color="#0000ff" />
</view>
</template>
<script>
import firebase from "firebase";
import Fire from "./../../api/firebaseAPI";
export default {
// Declare `navigation` as a prop
props: {
navigation: {
type: Object,
},
},
async mounted() {
await firebase.auth().onAuthStateChanged(function (user) {
this.navigation.navigate(user ? "App" : "Auth");
});
},
};
</script>
When I run this code above I get a white screen.
Maybe we should move the code in mounted to a method.
<script>
mounted(){
this.checkAuth()
},
...
methods:{
async checkAuth(){
await firebase.auth().onAuthStateChanged(function (user) {
if(user){
this.navigation.navigate("Auth")
}else{
this.navigation.navigate("App")
}
});
}
}
</script>
i m kind of new in React and Javascript in general. I m trying to make a checklist using a checkbox. In the frontend it works, more or less. My problem is that I m trying to get the state if a task is completed or not. I ve made an array with an object, (see MainContent code), but when i click the checkbox it returns in the console.log "undefined".
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
App Component
import React, { Component } from "react";
import Header from "./components/Header";
import MainContent from "./components/MainContent";
import "./styles.css";
class App extends Component {
render() {
return (
<div className="App">
<Header />
<MainContent />
</div>
);
}
}
export default App;
MainContent Component
import React, { Component } from "react";
import task from "../assets/task";
import ListItem from "../components/ListItem";
class MainContent extends Component {
constructor(props) {
super(props);
this.state = {
task: [
{
id: 1,
task: "task 01",
name: "pedro",
completed: null
},
{
id: 2,
task: "task 02",
completed: null
},
{
id: 3,
task: "task 03",
completed: null
}
]
};
this.handleChange = this.handleChange.bind(this);
}
handleChange = completed => {
alert("your task is", completed);
console.log("This task is", completed);
};
render() {
console.log("task render", this.task);
const taskComponents = this.state.task.map(data => (
<ListItem
key={data.id}
task={data.task}
id={data.id}
completed={data.completed}
handleChange={() => {
this.handleChange();
}}
/>
));
return <div>{taskComponents}</div>;
}
}
export default MainContent;
ListItem Component
import React, { Component } from "react";
let i = 1;
class ListItem extends Component {
render() {
return (
<div className="ListItem">
<p style={{ color: i % 2 ? "black" : "orange" }}>
<input
type="checkbox"
checked={this.props.completed}
onChange={() => this.props.handleChange(this.props.completed)}
/>
Task {i++}: <b>{this.props.task}</b>
</p>
</div>
);
}
}
export default ListItem;
I would expect to get from the handleChange the state of "completed".
Should i create an empty object to receive the checkbox state? Thanks for any help.
The onChange function should looks like this :
(event) => this.props.handleChange(event.value)
I'm not sure about the event.value but log the event, and the checkbox value should be inside.
Not sure what I am doing wrong here??
In a simple react-redux web app I can't get the new date to set.
The onChange should be setting the selection to the new state for the 'purchase_date'??
Here is my code...
import React, { Component } from 'react';
import { connect } from 'react-redux';
import DatePicker from 'react-datepicker';
import moment from 'moment';
import 'react-datepicker/dist/react-datepicker.css';
// CSS Modules, react-datepicker-cssmodules.css
// import 'react-datepicker/dist/react-datepicker-cssmodules.css';
class DateSelect extends Component {
constructor (props) {
super(props)
this.state = {
startDate: moment()
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(date) {
this.setState({
selected: date
});
}
render() {
return <DatePicker
selected={this.state.startDate}
onChange={this.purchase_date}
/>;
}
}
export default DateSelect;
///////
<TableRow selectable={false} key={id}>
<TableRowColumn>{item_description}</TableRowColumn>
<TableRowColumn>{purchase_date}</TableRowColumn>
<TableRowColumn id="count-me">${item_price}
**<DatePicker
selected={this.state.startDate}
onChange={this.purchase_date}
/>**
Firstly, you are binding your handler but aren't actually using it. Additionally, you may wish to pass in a date via your props so it can be set to an initial value that is not the current date (defaulting to current date if not specified:
class DateSelect extends Component {
constructor (props) {
super(props);
this.state = {
startDate: moment()
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(date) {
this.setState({
selected: date
});
}
render() {
return <DatePicker
selected={this.props.selected || this.state.startDate}
onChange={this.handleChange} // <- attaches handleChange to onChange
/>;
}
}
Now, down in your JSX for your table, you only need to call for your component. you should call your custom component instead of DatePicker so that it loads with your behaviors and allows you to do things like pass default or stored values to the components props:
<TableRow selectable={false} key={id}>
<TableRowColumn>{item_description}</TableRowColumn>
<TableRowColumn>{purchase_date}</TableRowColumn>
<TableRowColumn id="count-me">${item_price}
<!-- DateSelect component, passing the 'selected' prop as
an value in someStartDate -->
<DateSelect selected={someStartDate} />
I've been struggling passing a value from one component to another. It's a continuation of the issue from a previous question which was partially resolved: react-native tab navigator search box
I'm using tab navigator and here's my app setup:
index.js (renders tab setup)
router.js
searchHeader.js
tab1.js
tab2.js
etc
In index.js when a tab is changed I'm getting the name of the tab. I want to pass that to searchHeader.js to update the placeholder text.
As searchHeader.js isn't imported into index.js and not a direct child how do I pass it that value?
index.js
import React, { Component } from 'react';
import { Root, Tabs } from './config/router';
import { Alert,View } from 'react-native';
class App extends Component {
constructor(props) {
super(props);
this.state = {
searchText: '',
}
}
_getCurrentRouteName(navState) {
if (navState.hasOwnProperty('index')) {
this._getCurrentRouteName(navState.routes[navState.index])
} else {
if (navState.routeName==='One') {
this.setState({searchText:'Search One'})
}
if (navState.routeName==='Two') {
this.setState({searchText:'Search Two'})
}
if (navState.routeName==='Three') {
this.setState({searchText:'Search Three'})
}
if (navState.routeName==='Four') {
this.setState({searchText:'Search Four'})
}
}
}
render() {
return (
<Root onNavigationStateChange={(prevState, newState) => {
this._getCurrentRouteName(newState)
}} />
)
}
}
export default App;
router.js
...
export const Root = StackNavigator({
Tabs: {
screen: Tabs,
navigationOptions: {
header: <SearchHeader data={'Test'} />
}
},
}, {
mode: 'modal',
});
searchHeader.js
import React, { Component } from 'react';
import { View,Text,Dimensions,Alert } from 'react-native';
import { SearchBar } from 'react-native-elements';
class SearchHeader extends Component {
constructor(props) {
super(props);
this.state = {
placeholder: "Search One"
}
}
render() {
return (
<SearchBar
noIcon
containerStyle={{backgroundColor:'#fff'}}
inputStyle={{backgroundColor:'#e3e3e3',}}
lightTheme = {true}
round = {true}
placeholder={data}
placeholderTextColor = '#000'
/>
);
}
};
export default SearchHeader;
You could perhaps pass it as a navigation prop using the setParams method.
An alternative, depending on the scope of your app, would be to look at a state library such as Redux or MobX - but if it's a small app, it's overkill
For that you can use Redux, you will have a store where you can put shared properties and values,
Then your components can connect to that store and bind its props with the chosen reducer(s) and dispatch actions..
this structure may work:
class Home extends Component {
func(val) {
this.setState({value: val});
}
render() {
return (
<View>
<Two func={(val) => this.func(val)} />
</View>
)
}
}
class Two extends Component {
render() {
return (
<View>
<Button title="set" onPress={() => this.props.func('data')} />
</View>
)
}
}
I'm trying to execute a dummy test with enzyme over a component. the test is about to check the context. even though I'm writing the same code as enzyme's documentation the context is always empty.
import React from 'react';
import { shallow } from 'enzyme';
import Overlay from '../../../../app/components/Overlay/Overlay';
describe('<Overlay />', () => {
it.only('return a context', () => {
const wrapper = shallow(<Overlay />, { context: { foo: 10 } });
console.log(wrapper.context());
// expect(wrapper.context().foo).to.equal(10);
});
})
the test's output is:
<Overlay />
{}
✓ return a context
where am I wrong?
Since the details of Overlay component is not given, I assume the context is not used in it (pls check childContextTypes and getChildContext are defined properly)
For example, refer the explanation for contexts in react documents
I have taken the same example to enable the test,
import React from 'react';
export default class Button extends React.Component {
render() {
return (
<button style={{ background: this.context.color }}>
{this.props.children}
</button>
);
}
}
Button.contextTypes = {
color: React.PropTypes.string,
};
class Message extends React.Component {
render() {
return (
<div>
{this.props.text} <Button>Delete</Button>
</div>
);
}
}
class MessageList extends React.Component {
getChildContext() {
return { color: 'purple' };
}
render() {
const children = this.props.messages.map((message) =>
<Message text={message.text} />
);
return <div>{children}</div>;
}
}
MessageList.childContextTypes = {
color: React.PropTypes.string,
};
I've created the test for Button component as below,
import React from 'react';
import { shallow } from 'enzyme';
import { expect } from 'chai';
import Button from '../../src/components/SampleComp';
describe.only('<Button />', () => {
it('assert for context', () => {
const wrapper = shallow(
<Button />,
{ context: { color: 'red' } }
);
expect(wrapper.context().color).to.equal('red');
expect(wrapper.context('color')).to.equal('red');
});
});
<Button />
✓ assert for context
1 passing (214ms)
This will assert it correctly.