I am new to React so looking like how can I render the data of image, name and user name from render method of one component to other components.
class Avatar extends React.Component {
render() {
return (
<img src={''} />
)
}
}
class Label extends React.Component {
render() {
return (
<h1>Name: </h1>
)
}
}
class ScreenName extends React.Component {
render() {
return (
<h3>Username: </h3>
)
}
}
class Badge extends React.Component {
render() {
return (
<div>
<Avatar />
<Label />
<ScreenName />
</div>
)
}
}
And the render method is this. How to read this image username and name into other components and update the view. Tried using {this.props.name} and also {this.props.user.name} but I am getting name as undefined.
ReactDOM.render(
<Badge user={{
name: 'Tyler McGinnis',
img: 'https://avatars0.githubusercontent.com/u/2933430?v=3&s=460',
username: 'tylermcginnis'
}} />,
document.getElementById('app')
);
And the HTML is this
<div id='app'></div>
You pass data via the component's props. It looks like this:
class Avatar extends React.Component {
render() {
return (
<img src={this.props.img} />
)
}
}
class Label extends React.Component {
render() {
return (
<h1>{this.props.name}</h1>
)
}
}
class ScreenName extends React.Component {
render() {
return (
<h3>{this.props.username}</h3>
)
}
}
class Badge extends React.Component {
render() {
return (
<div>
<Avatar img={this.props.user.img}/>
<Label name={this.props.user.name} />
<ScreenName username={this.props.user.username} />
</div>
)
}
}
And after some refactoring, you end up with this:
const Avatar = ({img}) => (
<img src={img} />
);
const Label = ({name}) => (
<h1>{name}</h1>
);
const ScreenName = ({username}) => {
<h3>{username}</h3>
);
const Badge = ({user}) => (
<div>
<Avatar img={user.img}/>
<Label name={user.name} />
<ScreenName username={user.username} />
</div>
)
Note that here we made use of so called functional stateless components, which can make your code a lot shorter and often more elegant. See here.
You can pass the data via props
https://codesandbox.io/s/o4nz576jn5
Related
I am new to React and I am trying to make a simple application...I fetch some data from backend( a list with announces) and I make a list with them. So, I want that when I push to a button from that announce I want to go to another component where I can see details about that announce. I put my code:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
carData: null,
checkData: false
}
}
getData = () => {
fetch('http://localhost:8000/api/all-articles')
.then( (response) => response.json() )
.then( (response) => {this.setState({
carData : response,
checkData : true
})});
}
componentDidMount = () => {
this.getData();
}
displayCars = () => {
return(
this.state.carData.data.map( (object, index) => (
<CarCard key={index} name = {object.title} description={object.description} img={object.image} id={object.id}/>
) )
);
}
render() {
if(this.state.checkData){
return(
<div className="App">
<Title/>
<div className="cars">
{this.displayCars()}
</div>
</div>
);
}else {
return(
<div>Loading..</div>
);
}
}
}
export default App;
class CarCard extends React.Component {
render() {
console.log(this.goToCardInfo(this.props.id));
return(
<div className="card">
<Card>
<Card.Img variant="top" src={`http://localhost:8000/images/${this.props.img}`}/>
<Card.Body>
<Card.Title>{this.props.name}</Card.Title>
<Card.Text>
{this.props.description}
</Card.Text>
<Button variant="primary">See announce</Button>
</Card.Body>
</Card>
</div>
);
}
}
export default CarCard;
class InfoCard extends React.Component {
render() {
return(
<h2>hello</h2>
);
}
}
export default InfoCard;
I want to say that from backend I fetch id, title,description, price..I googled it but I didn't understand how can I make it..Thank you
I think you need react-router-dom
I recommend you learn it. Below is my implementation with router.
App.js
import {BrowserRouter as Router, Switch, Route} from "react-router-dom"
import Cars from "./Cars.js" // Change it to the correct path
import InfoCard from "./InforCard.js"
class App extends React.Component {
render() {
<Router>
<Switch>
<Route path="/cars" component={Cars}></Route>
<Route path="/cars/:id" component={InfoCard} exact></Router>
<Switch>
</Router>
}
}
export default App;
Cars.js
class Cars extends React.Component {
constructor(props) {
super(props);
this.state = {
carData: null,
checkData: false
}
}
getData = () => {
fetch('http://localhost:8000/api/all-articles')
.then( (response) => response.json() )
.then( (response) => {this.setState({
carData : response,
checkData : true
})});
}
componentDidMount = () => {
this.getData();
}
displayCars = () => {
return(
this.state.carData.data.map( (object, index) => (
<CarCard key={index} name = {object.title} description={object.description} img={object.image} id={object.id}/>
) )
);
}
render() {
if(this.state.checkData){
return(
<div>
<Title/>
<div className="cars">
{this.displayCars()}
</div>
</div>
);
}else {
return(
<div>Loading..</div>
);
}
}
}
export default Cars;
CarCard.js
import { withRouter } from "react-router-dom"
class CarCard extends React.Component {
render() {
console.log(this.goToCardInfo(this.props.id));
return(
<div className="card">
<Card>
<Card.Img variant="top" src = {`http://localhost:8000/images/${this.props.img}`}/>
<Card.Body>
<Card.Title>{this.props.name}</Card.Title>
<Card.Text>
{this.props.description}
</Card.Text>
<Button variant="primary"
onClick={() => this.props.history.push("/card/" + this.props.id)}>See announce</Button>
</Card.Body>
</Card>
</div>
);
}
}
export default withRouter(CarCard);
InfoCard.js
class InfoCard extends React.Component {
// you can get the id of the card like this
const url = window.location.hash;
const id = url.substring(url.lastIndexOf("/") + 1);
// use that id to query your car
render() {
return(
<h2>hello</h2>
);
}
}
export default InfoCard;
According to react docs
the code below will re-render all consumers every time the Provider re-renders because a new object is always created for value
So i made a simple example to test this:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'},
};
}
render() {
console.log('App');
return (
<>
<ThemeContext.Provider value={this.state.value}>
<ThemeContext.Consumer>
{(value)=>( <Toolbar test={value}/>)}
</ThemeContext.Consumer>
</ThemeContext.Provider>
<button onClick={this.handler}>click me</button>
</>
);
}
handler=()=>{
this.forceUpdate()
}
}
const app = <App />;
class Toolbar extends React.Component {
render() {
console.log('Toolbar');
return (
<div></div>
);
}
}
ReactDOM.render(app,mountNode);
It seems that in every click, even though the reference is the same, toolbar component re-renders along with provider. So what is wrong here?
Writing the consumer as direct children of App will cause them to render when App component re-renders instead you must write your code as
const ThemeContext = React.createContext();
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'},
};
}
render() {
console.log('App');
return (
<React.Fragment>
<ThemeContext.Provider value={this.state.value}>
{this.props.children}
</ThemeContext.Provider>
<button onClick={this.handler}>click me</button>
</React.Fragment>
);
}
handler=()=>{
this.forceUpdate()
}
}
const app = (<App>
<ThemeContext.Consumer>
{(value)=>( <Toolbar test={value}/>)}
</ThemeContext.Consumer>
</App>)
class Toolbar extends React.Component {
render() {
console.log('Toolbar');
return (
<div></div>
);
}
}
ReactDOM.render(app, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<div id="app"/>
try this:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'},
};
}
handler(){
this.forceUpdate()
}
render() {
console.log('App');
return (
<div>
<ThemeContext.Provider value={this.state.value}>
<ThemeContext.Consumer>
{(value)=>( <Toolbar test={value}/>)}
</ThemeContext.Consumer>
</ThemeContext.Provider>
<button onClick={this.handler}>click me</button>
</div>
);
}
}
const app = <App />;
class Toolbar extends React.Component {
render() {
console.log('Toolbar');
return (
<div></div>
);
}
}
ReactDOM.render(app,mountNode);
I have a parent component App.js which looks like this
export default class App extends React.Component {
constructor(){
super();
this.state = {
registerusername: '',
}
}
Now I have a child component ChildComp.js which is a direct child of App.js and looks like this
class ChildComp extends React.Component {
render() {
return (
<View>
<TextInput
placeholder="Username"
placeholderTextColor = 'black'
onChangeText={(registerusername) => this.setState({registerusername})}
/>
<Text>
{this.state.registerusername.split(' ').map((word) => word && '🍕').join(' ')}
</Text>
</View>
}
}
I am attempting to change print the pizza logo just like the react native document under the TextInput field. I am having a hard time understanding how I can do this when the state, registerusername is in parent component and the ChildComp is stateless. I am doing `this.setState({registerusername})} in my ChildComp but I dont think it is referencing the parent's state.
in app'
setName = (name) => {
this.setState({ registerusername: name })
}
render() {
return (
<div>
<ChildComp registerusername={this.state.registerusername} setName={this.setName} />
</div>
)
}
in ChildComp
< TextInput
placeholder = "Username"
placeholderTextColor = 'black'
onChangeText = {(e) => this.props.setName(e.target.value)}
/>
< Text >
{ this.props.registerusername.split(' ').map((word) => word && '🍕').join(' ') }
</Text >
I want to be able to update a child component property from both the parent and itself according to the last event.
For example:
class MyParent extends Component {
state ={
text:"";
}
render() {
return (
<View>
<MyChild text={this.state.text} />
<Button
onPress={()=>this.setState({text:"parent"})}
title="Update From Parent"
/>
</View>
);
}
}
class MyChild extends Component {
state ={
text:"";
}
componentWillReceiveProps(nextProps) {
if (nextProps.text!== this.state.text) {
this.setState({text:nextProps.text});
}
}
render() {
return (
<View>
{/* I want that the text field will be updated from the last event*/}
<Text>{this.state.text}</Text>
<Button
onPress={()=>this.setState({text:"child"})}
title="Update From Child"
/>
</View>
);
}
}
The issue is that componentWillReceiveProps is triggered each time the setState is called so the text property takes the value from the parent and not from the child.
How can I achive this result?
Thanks a lot
Elad
Manage your state through parent component and pass the function that will update the state of parent component in child component
class MyParent extends Component {
constructor(props) {
super(props);
this.state = {
text: "",
updateParentState: (newState) => this.setState(newState)
}
}
render() {
let { text, updateParentState } = this.state;
return (
<View>
<MyChild data={{ text, updateParentState }} />
<Button
onPress={() => updateParentState({ text: "parent" })}
title="Update From Parent"
/>
</View>
);
}
}
class MyChild extends Component {
constructor(props) {
super(props);
this.state = {
text: props.data.text
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.text !== this.state.text) {
this.setState({ text: nextProps.data.text });
}
}
render() {
let { updateParentState } = this.props.data;
return (
<View>
<Text>{this.state.text}</Text>
<Button
onPress={() => updateParentState({ text: "child" })}
title="Update From Child"
/>
</View>
);
}
}
You are missing this. in the setState call in child. please check if this is not the issue.
<Button
onPress={()=>setState({text:"child"})}
title="Update From Child"
/>
should be
<Button
onPress={()=>this.setState({text:"child"})}
title="Update From Child"
/>
I have a problem with refs on React Native. This is a simplified version of my code:
class Main extends React.Component {
constructor(props) {
...
this.refs = {};
}
render() {
if(this.state.page=="index") {
return(
<View>
<FlatList ref={flatlist => this.refs.flatlist = flatlist}> ... </FlatList>
<MyActionButton flatlist={this.refs.flatlist}/>
</View>
)
} else if (this.state.page="text"=){
return(
<Text> ... </Text>
)
}
}
}
class MyActionButton extends React.Component {
render(
return(
<ActionButton>
<ActionButtonItem onPress={() => {
console.log("AB props", this.props)
}} />
</ActionButton>
)
)
}
The app starts with this.state.page = "index" so when I press MyActionButton I see the log as expected, and things seem to work:
'AB props', {flatlist: {A LOT OF STUFF HERE}}
However If I change the state.page to "text" and then come back to "index" again, when I press MyActionButton I get:
'AB props', {flatlist: undefined}
I'm not sure why that prop gets undefined and how to fix it to make it point to the actual FlatList.
I don't like very much, but I managed to get it working by changing the reference to a getter funcion
class Main extends React.Component {
constructor(props) {
...
this.refs = {};
}
getFlatList() {
return this.refs.flatlist;
}
render() {
if(this.state.page=="index") {
return(
<View>
<FlatList ref={flatlist => this.refs.flatlist = flatlist}> ... </FlatList>
<MyActionButton flatlist={this.getFlatList.bind(this)}/>
</View>
)
} else if (this.state.page="text"=){
return(
<Text> ... </Text>
)
}
}
}