I'm really regarding props in React/React-Native. I have a parent view. In this view I'm getting the user data from a LocalStorage.['
import React, { Component } from 'react';
import { Container, Content, View } from 'native-base';
import NutrionalToolbar from '../../components/NutrionalToolbar';
import { AsyncStorage } from 'react-native';
export default class LogsScreen extends Component {
state = {
user: '',
}
componentWillMount() {
this._bootstrapAsync();
}
_bootstrapAsync = async () => {
const user = await AsyncStorage.getItem('user');
this.setState({ user: JSON.parse(user) })
};
render() {
return (
<Container>
<NutrionalToolbar user={this.state.user} />
</Container>
);
}
}
Now inside the NutrionalToolbar component I have this.
import React, { Component } from 'react';
import { View } from 'native-base';
class NutrionalToolbar extends Component {
constructor(props) {
super(props)
console.log(this.props) // This renders an empty user object
}
render() {
console.log(this.props) // This renders the user object with values
return (
<View>
</View>
);
}
}
export default NutrionalToolbar;
How can I get this.props values inside the constructor. I'm getting the values inside render method. Why isn't working inside the constructor?
I would recommend looking into the componentDidUpdate lifecycle hook because, even if you could access the initial user prop in the constructor, you wouldn't be able to access updates to that prop in the constructor.
import React, { Component } from 'react';
import { View } from 'native-base';
class NutrionalToolbar extends Component {
componentDidUpdate() {
console.log(this.props) // This will always log the current props
}
render() {
return (<View></View>);
}
}
export default NutrionalToolbar;
Related
I've got a parent component Course that is able to get state from redux and I'm able to log that out successfully:
import React, { Component } from "react";
import { connect } from "react-redux";
import SchoolWrapper from "../SchoolWrapper";
export class Course extends Component {
constructor(props) {
super(props);
console.log("Props in course", props);
}
render() {
return (
<>
<SchoolWrapper>Wrapped component</SchoolWrapper>
</>
);
}
}
const mapStateToProps = (state) => ({
user: state.user,
});
export default connect(mapStateToProps)(Course);
Nested in the Course component is another component SchoolWrapper that is able to get props from redux state:
import React, { Component } from "react";
import { connect } from "react-redux";
import { Nav } from "./Student/Nav";
export class SchoolWrapper extends Component {
constructor(props) {
super(props);
console.log("SchoolWrapper props", props);
}
render() {
return (
<>
<Nav />
</>
);
}
}
const mapStateToProps = (state) => ({
user: state.user,
});
export default connect(mapStateToProps)(SchoolWrapper);
However, the Nav component or any other component nested at this level is not able to access state from redux.
import React, { Component } from "react";
import { connect } from "react-redux";
export class Nav extends Component {
constructor(props) {
super(props);
console.log("Nav props: ", props);
}
render() {
return (
<div>
nav goes here...
</div>
);
}
}
const mapStateToProps = (state) => ({
user: state.user,
});
export default connect(mapStateToProps)(Nav);
Where am I going wrong?
I think you're importing Nav wrong, here you're using a "default" export:
export default connect(mapStateToProps)(Nav);
But you try to use a "named" import:
import { Nav } from "./Student/Nav";
Nav should be imported as a "default":
import Nav from "./Student/Nav"
There are 2 separate components that fetch data through api. The code below is for the first component and then there is another component that fetch other data of the same company through another api and the code of that one is exactly the same except the api link. How to fetch the data from the other api in this component so there is no need for 2 different components.
import React, { Component, Fragment } from 'react'
import axios from 'axios'
class CompanyProfile extends Component {
constructor(){
super();
this.state={
Company:[]
}
}
componentDidMount(){
axios.get('http://localhost:3000/link').then(response =>{
**/////////for example axios.get('http://localhost:3000/link2') added here.**
this.setState({Company:response.data});
});
}
render() {
const cp = this.state.Company;
const CompanyView = contact.map((cp,i)=>{
**/////then mapped here.**
return <div>
<p>{cp.name}</p>
<p>{cp.type}</p>
<p>...other data</p>
**//// and then displayed here <p>{cp.CompanyProducts.data}</p>**
</div>
});
return (
<div>
{CompanyView}
</div>
)
}
}
export default CompanyProfile
I am not sure about your question. We can use container and presentational components.
A container does data fetching and then renders its corresponding sub-component. That’s it.
Refactor the CompanyProfile component to a stateless presentational component. Pass the company data from the remote API server to it from the container component.
So that we can reuse the CompanyProfile component.
CompanyProfile.jsx:
import React, { Component } from 'react';
class CompanyProfile extends Component {
render() {
const { campany } = this.props;
const CompanyView = campany.map((cp, i) => {
return (
<div>
<p>{cp.name}</p>
<p>{cp.type}</p>
<p>...other data</p>
<p>{cp.CompanyProducts.data}</p>
</div>
);
});
return <div>{CompanyView}</div>;
}
}
export default CompanyProfile;
Parent1.tsx:
import React, { Component } from 'react';
import axios from 'axios';
import CompanyProfile from './CampanyProfile';
export default class Parent extends Component {
constructor(props) {
super(props);
this.state = {
company: [],
};
}
componentDidMount() {
axios.get('http://localhost:3000/link').then((response) => {
this.setState({ company: response.data });
});
}
render() {
return <CompanyProfile company={this.state.company} />;
}
}
Parent2.jsx:
import React, { Component } from 'react';
import axios from 'axios';
import CompanyProfile from './CampanyProfile';
export default class Parent2 extends Component {
constructor(props) {
super(props);
this.state = {
company: [],
};
}
componentDidMount() {
axios.get('http://localhost:3000/link2').then((response) => {
this.setState({ company: response.data });
});
}
render() {
return <CompanyProfile company={this.state.company} />;
}
}
This is child component as i can you Props here
Child Component:
import React from "react";
const PeopleList = props => {
console.log("child Props :", props.data);
const list = props.data.map(item => item.name);
return <React.Fragment>{"list"}</React.Fragment>;
};
export default PeopleList;
Main Component:
import React, { Component } from "react";
import { connect } from "react-redux";
import { fetchPeople } from "../actions/peopleaction";
import PeopleName from "../containers/peopleName";
class Main extends Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
this.props.dispatch(fetchPeople());
}
render() {
const { Error, peoples } = this.props;
console.log("data", peoples);
return (
<div className="main">
{"helo"}
<PeopleName data={peoples.results} />
</div>
);
}
}
const mapStateToProps = state => {
return {
peoples: state.peoples.peoples,
error: state.peoples.error
};
};
export default connect(mapStateToProps)(Main);
If i iterate the props multi objects array i can face Map is not define issue;
I need to iterate the props.data multi objects array in child component and i get object from Redux store. once component loaded the redux store.
can you please some one help me on this.
you can find whole code below mentioned
Try this It works in your codesandbox.
{peoples.results && <PeopleName data={peoples.results} />}
I have a container which has access to the Redux state and maps a certain pieces of that state to its props, the piece I'm interested in is 'coins' so
this.props.coins
Using console.log() I can see that when rendering the container I have access to that piece of state.
This container houses one component that receives a callback function and this previously mentioned piece of state, coins, via its own props in
onClickHandler() && coinData
The container has a function to handle the callback called
_handleClick()
In this function for some reason this.props doesn't give access to the same coins I was able to access in the render function but has access to the props that I'm passing to the component, props I thought would belong to the component. So from _handleClick() in the container I have access to
this.props.onClickHandler() && this.props.coinData
but not
this.props.coins
which is what I was expecting to have access to from anywhere within my container. I get the error in the title of the post when I try to access this.props.coins in my callback handler _handleClick() but why is that and why do I have access to the props that should belong to the corresponding child component? Is there any way that I can access this.props.coins from the _handleClick() call?
My container:
import React, { Component } from 'react';
import '../App.css';
import { connect } from "react-redux";
import ChartSelectMenu from '../components/ChartSelectMenu';
import { selectCoinForChart } from '../actions/index';
class ChartSelectMenuContainer extends Component {
constructor(props) {
super(props);
}
_handleClick(ticker) {
//event.preventDefault();
console.log("Clicked: ", ticker);
console.log("coin_list: ", this.props);
const coin_list = this.props.coins;
//
for (let i=0; i<coin_list.length; i++) {
if (coin_list[i].ticker === ticker) {
this.props.dispatch(selectCoinForChart(ticker));
}
}
}
render() {
console.log("Container props on render(): ", this.props);
return (
<ChartSelectMenu
onClickHandler={this._handleClick}
coinData={this.props.coins}
/>
);
}
}
function mapStateToProps({ auth, coins, selectedCoin }) {
return { auth, coins, selectedCoin };
}
export default connect(mapStateToProps)(ChartSelectMenuContainer);
It's component:
import React, {Component} from 'react';
import Paper from 'material-ui/Paper';
import Menu from 'material-ui/Menu';
import MenuItem from 'material-ui/MenuItem';
const style = {
display: 'inline-block',
margin: '16px 0px 16px 0px',
};
class ChartSelectMenu extends Component {
constructor(props) {
super(props);
}
_renderMenuItems() {
if (this.props === null) {
return <h3>Loading...</h3>;
} else {
return(this.props.coinData.map((coin) => {
return <MenuItem
key={coin.ticker}
onClick={this.props.onClickHandler.bind(this, coin.ticker)}
primaryText={coin.ticker}
/>
}));
}
}
render() {
//console.log('ChartSelectMenu props: ', this.props);
return (
<div>
<Paper style={style}>
<Menu>
<ul>
{this._renderMenuItems()}
</ul>
</Menu>
</Paper>
</div>
)
}
}
export default ChartSelectMenu;
When #MukulSharma commented 'use var self = this inside your function' I thought to try to bind the _handleClick function in the constructor of the container and it worked.
The solution:
import React, { Component } from 'react';
import '../App.css';
import { connect } from "react-redux";
import ChartSelectMenu from '../components/ChartSelectMenu';
import { selectCoinForChart } from '../actions/index';
class ChartSelectMenuContainer extends Component {
constructor(props) {
super(props);
this._handleClick = this._handleClick.bind(this);
}
_handleClick(ticker) {
//event.preventDefault();
console.log("Clicked: ", ticker);
console.log("coin_list: ", this.props);
const coin_list = this.props.coins;
//
for (let i=0; i<coin_list.length; i++) {
if (coin_list[i].ticker === ticker) {
this.props.dispatch(selectCoinForChart(ticker));
}
}
}
render() { ...
I have a parent component that I want to be tabs for multiple children. For some reason, my child component has more props data than the parent.
Parent component
import React, { Component} from 'react';
import { Link } from 'react-router';
import { connect } from 'react-redux';
class TerritoryTabs extends Component {
componentWillMount() {
console.log('this is the parent props (tabs)')
console.log(this.props);
}
render() {
return (
{this.props.children}
);
}
}
export default connect(null, null)(TerritoryTabs);
Child component
import React, { Component} from 'react';
import { Link } from 'react-router';
import { connect } from 'react-redux';
import { reduxForm } from 'redux-form';
import { getTerritoryGeographies } from '../actions/index';
import TerritoryTabs from './territory-tabs';
class TerritoryGeographyList extends Component {
componentWillMount() {
console.log('this is child props (TerritoryGeographyList)');
console.log(this.props);
this.props.getTerritoryGeographies(this.props.params.id);
}
render() {
return (
<TerritoryTabs>
<div>This list goes here</div>
</TerritoryTabs>
);
}
}
function mapStateToProps(state) {
return { territoryGeographies: state.territoryGeographies.all
};
}
export default connect(mapStateToProps, { getTerritoryGeographies })(TerritoryGeographyList);
Here is what the console prints.
The wrap component should be called "parent". Example:
<Parent>
<Child />
</Parent>
So, in your case, fix this line:
class TerritoryTabs extends Component {
componentWillMount() {
console.log('this is the child props (tabs)') // <-- Fix this line, it should be the "child"
console.log(this.props);
}
and this line:
class TerritoryGeographyList extends Component {
componentWillMount() {
console.log('this is parent props (TerritoryGeographyList)'); // <-- fix this line, it should be "parent"
console.log(this.props);
this.props.getTerritoryGeographies(this.props.params.id);
}