I am getting unrechable code warning in react native - react-native

I am following this question's first answer to create a common parent for two of my components
import React, {Component} from 'react';
import ButtonSubmit from './ButtonSubmit'
import Form from './Form'
export default class ParentofButtonandForm extends Component {
constructor() {
super();
this.state = {
username: '',
password : '',
};
}
changeFirst(receivedUN,reaceivedPW) {
this.setState({
username: receivedUN,
password:reaceivedPW
});
}
render() {
return (
<Form username={this.state.username} password={this.state.password} changeFirst={this.changeFirst.bind(this)}/>
<ButtonSubmit username={this.state.username} password={this.state.password}/>
)
}
}
But i get unrechable code error in
<ButtonSubmit username={this.state.username} password={this.state.password}/>
I dont know what i am doing wrong. I also get a ':expected' warning in this.state.username.

You are returning two components from render functions. Either you wrap <Form> and <Button> into another component, may be View OR you can return a component array from render function.
Wrapping inside View
render() {
return (
<View>
<Form .../>
<ButtonSubmit .../>
</View>
)
}
Returning array of components, link
render() {
return [
<Form .../>,
<ButtonSubmit .../>
];
}
Hope this will help!

Related

React Relay createFragmentContainer and QueryRenderer data flow

I've been working through the examples in relay's document for QueryRenderer https://relay.dev/docs/en/query-renderer and FragmentContainer https://relay.dev/docs/en/fragment-container
I'm confused as to how the data is meant to be accessed by the Components wrapped in the HOC createFragmentContainer.
I have a top level QueryRenderer:
function renderFunction({error, props}) {
...
if (props) {
// Added todoList as a prop with a distinct name from tdlist which
// is meant to be passed in by createFragmentContainer
return <TodoList todoList = {props.todoList} />
}
...
}
export default function ContainerWithQueryRenderer() {
return (
<QueryRenderer
environment={environment}
query={graphql`
query ContainerWithQueryRenderer_Query {
todoList {
title
todoListItems { text isComplete}
}
}`}
render = { renderFunction }
/>
);
}
and a TodoList component that defines what data is needed in a graphql fragment:
import React from 'react';
import TodoItem from './TodoItem.js';
import { createFragmentContainer } from 'react-relay';
import graphql from 'babel-plugin-relay/macro';
function TodoList(props) {
console.log('TodoList props:',props);
if (props && props.todoList && props.todoList.todoListItems && props.todoList.title) {
return (
<div className='list-container'>
<div className='list-header'>
<div className='list-header-label'>{props.todoList.title}</div>
</div>
<div className='list'>{props.todoList.todoListItems.map( (item, key) => <TodoItem key = {key} item={item} />)}</div>
</div>
);
} else {
return null;
}
}
export default createFragmentContainer(TodoList,{
tdlist: graphql`
fragment TodoList_tdlist on TodoList {
title
todoListItems {
...TodoItem_item
}
}
`,
})
and a child TodoListItem
import React from 'react';
import { createFragmentContainer } from 'react-relay';
import graphql from 'babel-plugin-relay/macro';
function TodoItem(props) {
return <div className='list-item'>
<div className='list-item-label'>{props.item.text}</div>
{props.item.isComplete ?<div className='list-item-buttons'>Done</div>:null}
</div>
}
export default createFragmentContainer( TodoItem,{
item: graphql`
fragment TodoItem_item on Todo {
text isComplete
}
`
});
My understanding is that the createFragmentContainer for the TodoList will inject the data from the TodoList_tdlist fragemnt as the TodoList props.tdlist), shaped as per the shape of the graphql query.
However, this appears to not be happening. I get a warning in the console:
Warning: createFragmentSpecResolver: Expected prop `tdlist` to be supplied to `Relay(TodoList)`, but got `undefined`. Pass an explicit `null` if this is intentional.
What is the job of the createFragmentContainer if it is not to pass in the tdlist?
I tried to pass the todoList data explicitly in by changing
return
to
return
(the same prop name passed in by createFragmentContainer, I (understandably) get a different error:
Warning: RelayModernSelector: Expected object to contain data for fragment `TodoList_tdlist`, got `{"title":"Your to-do list","todoListItems":[{"text":"Brush teeth","isComplete":false},....
I think the root of my confusion is not understanding how the fragments that define the data dependencies interact with the QueryRenderer. Do I need to define the query to pull in every possible piece of data that could ever be needed, and the point is that relay will only query what is needed by looking at the graphql fragments of the components that are being rendered now, and will re-query if that changes, updating props as it gets new data?
Do I need to pass props down to fragment containers as props explicitly, or if they are a descendant of a QueryRenderer that requests their data, will the createFragmentContainer be able to access it via the relay environment?
Here is my graphql.schema to assist:
type Query {
todoList: TodoList!
}
type Todo {
text: String!
isComplete: Boolean!
}
type TodoList {
title: String!
todoListItems: [Todo]!
}
You must name the descendant fragment container's GraphQL fragment in your QueryRenderer. Without identifying the fragment, react-relay has relay no link between the QueryRenderer and the descendant FragmentContainer components. In your question, the query prop passed to QueryRenderer is
query ContainerWithQueryRenderer_Query { todoList { title todoListItems { text isComplete }}}
instead of
query ContainerWithQueryRenderer_Query { TodoList_tdlist }
Also, because the QueryRenderer works hand in hand with the Fragment Containers, it is simpler to iterate the todoListItems in the Query Renderer, and use a fragment for the TodoItem_item. Hence below I have merged the above <ContainerWithQueryRenderer /> and <TodoList />
This approach works:
TodoListWithQueryRenderer.js:
function renderFunction({error, props}) {
...
if (props) {
return (
<div>
<div>
<div>{props.todoList.title}</div>
</div>
<div>{props.todoList.todoListItems.map( (item, key) => <TodoItem key = {key} item={item} /> )}</div>
</div>
);
}
...
}
export default function TodoListWithQueryRenderer() {
return (
<QueryRenderer
environment={environment}
query={graphql`
query TodoListWithQueryRenderer_Query { todoList {todoListItems {...TodoItem_item } title} }
`}
render = { renderFunction }
/>
);
}
with only one descendant component required as the above merges the ContainterWithQueryRenderer with TodoList components.
TodoItem.js:
import React from 'react';
import { createFragmentContainer } from 'react-relay';
import graphql from 'babel-plugin-relay/macro';
function TodoItem(props) {
return <div>
<div>{props.item.text}</div>
{props.item.isComplete ? <div>Done</div> : null}
</div>
}
export default createFragmentContainer( TodoItem,{
item: graphql`
fragment TodoItem_item on Todo {
text isComplete
}
`
});

React children's when using HOC to wrap parent

I am using React 16.8.6 and I have the following structure:
page.js
<ParentComponent id="testData">
<ChildComponent value={data => data.text} />
</ParentComponent>
parentComponent.tsx
export default class ParentComponent extends React.PureComponent<IParentProps> {
...
render() {
const items = this.props.children;
<MiddleComponent items={items} />
}
}
ParentContainer.ts
import { withTranslation } from 'react-i18next';
import ParentComponent from './ParentComponent';
export default withTranslation()(ParentComponent);
I need to know inside of MiddleComponent the element type (not as a String but as a React element since I am going to create a new Element based on it) of each child (so, in this case I should have ChildComponent), but when I inspect with chrome, all my children have a I18nextWithTranslation type...
Any idea how to fix this? Or if this is maybe a known bug?
If I don't use any hoc at all, when I write child.type it returns me ChildComponent(props). But this is not true to when I am using hocs to wrap the parent...
The issue was very stupid...
I was importing the <ChildComponent> as a default import even though the child was not exported as default.
Basically
import ChildComponent from '' instead of import { ChildComponent } from ''
In the example below, we're setting Component.displayName on our components so we can access that property in parents. This is a super trivial example that could be expanded to work with an array of children if needed.
const ChildComponent = () => {
return <div>child render</div>
}
ChildComponent.displayName = "MyComponentName"
const ParentComponent = ({ children }) => {
// This is the type of component.. should output "MyComponentName"
const childType = children.type.displayName
return (
<div>
<h1>Render Children</h1>
{children}
</div>
)
}
function App() {
return (
<ParentComponent>
<ChildComponent />
</ParentComponent>
)
}

Using states and props in React Native

Can I use a child components state in App.js? I mean, in a child component I have a variable for example i = 5 and I would like to use this in App.js. In App.js this.state.i shows 0.
This is a very basic pattern in react so maybe just read through the official docs oder do some tutorials for getting started with react.
But to help you out on this you need to pass down a function to your child that sets the state in <App/>
So something like this:
App:
this.state { i : 0 }
updateState() {
this.setState(i: i + 1); // or whatever
}
render() {
return (
<>
<Child updateState={this.updateState} />
</>
....
Child:
<div onClick={props.updateState}>Click me</div>
On app.js do this;
constructor(props) {
this.updateI=this.updateI.bind(this)
super(props)
this.state = {
i:0
}
}
updateI(i){
this.setState({i})
}
render() {
return (
<View >
<Child updateI={this.updateI}/>
</View>
)
}
on your child do this:
this.props.updateI(5);

How can I pass a component as a prop in React Native?

In my AutoSuggest Component (which renders FlatList), I would like to render different types of cells.
I'd like to pass different Components into AutoSuggest, such as:
<Suggest
customCell={<SimpleUserCell/>} //or any type of cell
/>
Inside Suggest.js, my render will look like this:
render(){
<FlatList
renderItem={(props) => {
return(
<this.props.customCell extraData={this.suggestData}/>
)
}}
/>
}
How can I achieve this?
To pass a component as a prop in React Native you can do the following, can be seen at: https://codesandbox.io/s/6v24n3q92z Hopefully this helps. You will need to extrapolate to get your specific use case working.
class ComponentOne extends React.Component {
render() {
return (
<div>
I am Component One see my array
<ul>{this.props.extraData.map(number => <li>number {number}</li>)}</ul>
</div>
);
}
}
class Suggest extends React.Component {
render() {
var anArray = [1, 2, 3, 4, 5];
var CustomComponent = this.props.customCell;
return <CustomComponent extraData={anArray} />;
}
}
function App() {
return <Suggest customCell={ComponentOne} />;
}

React Dynamic tag name

Assuming the following and all the components/fus/fci/ssg have just a single h1 with a site props. I want to understand why it is a valid react element yet these are not showing equally rendered. That is one has the h1 element and the other doesn't. The idea was to not create large component with toggles for different sites and each site would be swapped out based on the nav pick. I don't see anything documented for this unless I missed it...
{this.state.renderSite}
<Fci site="Fci"/>
import React from 'react';
import styles from './App.css';
import Nav from '../components/Nav.js'
import Fus from '../components/Fus.js'
import Fci from '../components/Fci.js'
import Ssg from '../components/Ssg.js'
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {renderSite: '', site: 'default' };
this.pickSite = this.pickSite.bind(this);
}
pickSite(site){
this.setState({renderSite: React.createElement(site, {"site":site})});
this.setState({site: site});
console.log( React.isValidElement(this.state.renderSite));
}
render() {
return (
<div className={styles.app}>
<Nav site={this.pickSite.bind(this)} />
{this.state.renderSite}
<Fci site="Fci"/>
</div>
);
}
}
The Nav
import React from 'react';
export default class Nav extends React.Component {
constructor(props) {
super(props);
this.update = this.update.bind(this);
}
update(e) {
this.props.site(e.target.dataset.site);
}
render(){
return (
<div>
<button onClick={this.update} data-site="Ssg"> SSG </button>
<button onClick={this.update} data-site="Fci"> FCI </button>
<button onClick={this.update} data-site="Fus"> FUS </button>
</div>
);
}
}
The problem is when you create the element you are passing a string (data-site value), not a component reference. So it ends up like this:
React.createElement("Fci");
As opposed to:
React.createElement(Fci);
Using a string will create a simple HTML element, not a component with with its own rendered content.
You could create a component map like this:
const componentMap = {
"Fci": Fci,
"Fus": Fus,
"Ssg": Ssg
}
Then from your string you can resolve a component reference:
React.createElement(componentMap[site], {site: site});
Or you could pass a component reference from your Nav:
<button onClick={this.update.bind(this, Ssg, "Ssg"}> SSG </button>
update(component, site, e) {
this.props.site(component, site);
}
pickSite(component, site) {
React.createElement(component, {site: site});
}