React function not being invoked, unless calling it directly - reactjs

I am trying to generate a component dynamically and render the component as a return from a function.
import React, { Component } from 'react';
import HelloWorld from './helloWorld';
export default class BaseComponent extends Component {
constructor(props) {
super(props)
this.getFields = this.getFields.bind(this)
}
getFields() {
let temp = { hi: 'Hello', world: 'World!' }
const test = temp.map(function(val, i) {
return <HelloWorld key={i} val={val} />
})
return test
}
render() {
return (
<div className="container">
{this.getFields}
</div>
);
}
}
But this function is not being invoked unless I use {this.getFields()} in my render method. Why can't I just use {this.getFields}, as that is bound in the constructor and hence should render the value. What am I missing?

You need to call the method from render function to use the returned value and not assign it and hence you need {this.getFields()}
render() {
return (
<div className="container">
{this.getFields()}
</div>
);
}

You need to invoke the function:
{this.getFields()}

Related

How to limit queryselector to a react component

I have a react component with a list of child-components. In the child-component I want to target a specific DOM element e.g., to change the color in its ComponentDidMount method. How would I do this?
Parent component
export class ListComponent extends Component<...> {
render(): ReactNode {
return (
<div>
<ListItemComponent key="123"/>
<ListItemComponent key="456"/>
<ListItemComponent key="789"/>
</div>
);
}
}
Child component
export class ListComponent extends Component<...> {
componentDidMount(): void {
// const elementToChange = document.queryselector(".toTarget"); // Only works for the first element as it only targets the first on the page
const elementToChange = THISREACTCOMPONENT.queryselector(".toTarget");
elementToChange.style.backgroundColor = "123123";
}
render(): ReactNode {
return (
<div>
<div className="toTarget">
</div>
);
}
}
So, the question is, what should be instead of THISREACTCOMPONENT? How to target an element exclusively within the react component?
use a react ref.
Refs were created so you won't have to use queryselector, as interacting directly with the dom may lead to react bugs further down the line.
export class ListComponent extends Component<...> { {
constructor(props) {
super(props);
this.myRef = React.createRef(); // Get a reference to a DOM element
}
componentDidMount(): void {
const elementToChange = this.myref.current;
elementToChange.style.backgroundColor = "123123";
}
render() {
return (
<div>
<div className="toTarget" ref={this.myRef}> // binds this element to the this.myref variable
</div>
)
}
}
You could use Document.querySelectorAll to get all matching elements
document.querySelectorAll returns an array of matching element.
Then you would do it like so:
componentDidMount(): void {
const elements = document.querySelectorAll(".toTarget");
elements.forEach((el) => {
el.style.backgroundColor = "123123";
});
}

React Context not passing data to its child components

I am a beginner in React. Looking at a few medium articles and React docs(which is complicated) I have tried to implement this very basic Context API.
I have missed some basic point which is the reason why I haven't got the correct result which is to pass data through the components tree and access them in the child component.
Please let me know how to correct given code snippet and what have I missed.
import React from 'react';
import './index.css';
const AppContext = React.createContext();
function GreenBox () {
return <div className='green-box'>
<AppContext.Consumer>
{(context) => context.value}
</AppContext.Consumer>
</div>
}
function BlueBox () {
return <div className='blue-box'><GreenBox/></div>
}
class RedBox extends React.Component {
render() {
return <div className='red-box'>
<AppContext.Consumer>
{(context) => context.value}
</AppContext.Consumer>
<BlueBox/>
</div>
}
}
class Context extends React.Component {
state = {
number: 10
}
render() {
return (
<AppContext.Provider value = {this.state.number}>
<RedBox/>
</AppContext.Provider>
)
}
}
export default Context;
The value you set in the Provider will be the argument received in the render props function in Consumer, so instead of accessing the number you're expecting with context.value, you should just change to context.

passing an event to a child component in React

I'm new to React and this is a very noob question, but I don't understand why this is not working.
I'm trying to build a simple todo List.
My TodoList.js Component looks like this:
import React, {Component} from 'react';
import TodoItem from './TodoItem';
export default class TodoList extends Component{
constructor(props){
super(props);
this.state = {
todos:[
{
title:"todo1"
},
{
title:"todo3"
},
{
title:"todo2"
}
]
}
}
handleRemove(idx){
alert('works');
}
render(){
var todos = this.state.todos.map(function(t,idx){
return(<TodoItem
remove={this.handleRemove.bind(this,idx)}
title={t.title}
/>)
})
return (
<div>
<h1>To do</h1>
<div>{todos}</div>
</div>
)
}
}
My child Component looks like this:
import React, {Component} from 'react';
export default class TodoItem extends Component{
render(){
return (
<div>{this.props.title}
<button onClick={this.props.remove}>X</button>
</div>
)
}
}
But I get a TypeError with "Cannot read property 'handleRemove' of undefined". I'm wondering why inside the map function {this} is undefined?
I tried to put this this.handleRemove = this.handleRemove.bind(this) into the constructor.
Didn't change anything. Shouldn't this also be defined inside the .map() ?
You need to put this as the second argument
If a thisArg parameter is provided to map, it will be used as
callback's this value. Otherwise, the value undefined will be used as
its this value. The this value ultimately observable by callback is
determined according to the usual rules for determining the this seen
by a function.
on map:
render(){
var todos = this.state.todos.map(function(t,idx){
return(<TodoItem
remove={this.handleRemove.bind(this,idx)}
title={t.title}
/>)
}, this)
return (
<div>
<h1>To do</h1>
<div>{todos}</div>
</div>
)
}
}
Alternatively, you can use an ES6 arrow function to automatically preserve the current this context:
var todos = this.state.todos.map((t,idx) => {
return(<TodoItem
remove={this.handleRemove.bind(this,idx)}
title={t.title}
/>)
})

Call function from another React component

My first component is as follow:
const hellos = ['Hola', 'Salut', 'Hallo', 'Ciao', 'Ahoj', 'Annyeong-haseyo', 'Aloha', 'Howdy', 'Ni Hao', 'Konnichiwa']
export class Welcome extends Component {
constructor(props) {
super(props);
this.state = {
errors: []
};
}
sayHello = function() {
return hellos[Math.floor((Math.random()*hellos.length))];
}
render() {
return (
<div className="Welcome">
</div>
);
}
}
I want to be able to call sayHello() from another component. All answers I've seen so far talk about parent and child relationships but in this case the two components don't have any relationship. I thought of something like this but it doesn't do the job:
import { Welcome } from './Welcome'
export const Life = () => (
<div className="Life">
<p>{ Welcome.sayHello() }</p>
</div>
)
I would like to get a random element of the hellos array printed in Life.
There are a number of ways you could achieve this:
You can do this by creating the sayHello function and using it simply as a named-function.
hello.js
const hellos = ['Hola', 'Salut', 'Hallo', 'Ciao', 'Ahoj', 'Annyeong-haseyo', 'Aloha', 'Howdy', 'Ni Hao', 'Konnichiwa'];
const sayHello = function() {
return hellos[Math.floor((Math.random()*hellos.length))];
};
export { sayHello };
Then you can import into which ever component you wish to share the functionality:
import { sayHello } from './hello';
class CompA extends React.Component {
render() {
return <span>{sayHello()}</span>;
}
}
class CompB extends React.Component {
render() {
return <span>{sayHello()}</span>;
}
}
render(<span>
<CompA />
<CompB />
</span>, document.querySelector('#app'));
Created a https://www.webpackbin.com/bins/-KkgrwrMGePG4ixI0EKd
Another way, is to simply define your sayHello Function as static.
static sayHello() {
return hellos[Math.floor((Math.random()*hellos.length))];
}

react render values from an array gives error

I have react component like:
class UserList extends Component {
render() {
const {users} = this.props
users.forEach(function(user){
console.log(user.name)
if(user.photos){
console.log(user.photos.data[0].source)
return (
<div>
<p>{user.name}</p>
</div>
)
}
})
}
}
export default UserList
But it is giving me error saying should return valid react component but returned array or undefined..
The return function should return the component right ?
What am I missing here ??
As the error states you need to return a valid React element.
The fix is to return a DOM node from your render, a div for example.
class UserList extends Component {
render() {
return <div></div>;
}
}
Further more using .forEach will not return a valid React element to the div, use .map instead to produce an array that you render.
class UserList extends Component {
render() {
return <div>{
this.props.users
.filter(user => user.photos)
.map((user) => {
return <li>{ user.name }</li>;
}}
</div>;
}
}

Resources