react call a bound method in render - javascript

I'm trying to call my method onModelSelect in render()
If I call it this.onModelSelect(model.id)) I then get the error Warning: setState(...): Cannot update during an existing state transition (such as withinrender). Render methods should be a pure function of props and state. However it does output to console.log
So I am trying to call it like I would with an event handler ()=>this.onModelSelect(model.id)) but this doesn't output anything to console.log
what is the correct syntax to use to call my method??
export default class App extends Component {
render() {
onModelSelect = (modelId) => {
this.props.selectModel(modelId);
this.props.setModelSelected(true);
console.log('test')
console.log('modelId',modelId)
}
return(
<div>
{this.props.models.length === 1 && this.props.models.map(model => ()=>this.onModelSelect(model.id))}
</div>
)
}
}

You shouldn't call anything containing this.setState from your render method.
Actually, your this.onModelSelect(model.id) would return Undefined function error because you have to define onModalSelect function in your component not in your render() function
export default class App extends Component {
onModelSelect = (modelId) => {
this.props.selectModel(modelId);
this.props.setModelSelected(true);
console.log('test')
console.log('modelId',modelId)
}
render() {
return(
<div>
{this.props.models.length === 1 && this.props.models.map(model => ()=>this.onModelSelect(model.id))}
</div>
)
}
}

Try putting your onModelSelect method outside the render method

There is a issue when you write like this:
.map(model => ()=>this.onModelSelect(model.id))
This says that .map callback returns function which in turn needs to be called to execute your function. Instead it should be:
.map(model => this.onModelSelect(model.id))
Also .map callback should return some value which in turn will be appended to array and will be rendered inside element.
You should create onModelSelect method outside render function:
export default class App extends Component {
onModelSelect = (modelId) => {
this.props.selectModel(modelId);
this.props.setModelSelected(true);
console.log('test')
console.log('modelId',modelId)
}
render() {
return(
<div>
{this.props.models.length === 1 && this.props.models.map(model => this.onModelSelect(model.id))}
</div>
)
}
}
Or if there is a legit use case and you want to put it in render function call it directly and not with this. Consider below code:
export default class App extends Component {
render() {
let onModelSelect = (modelId) => {
this.props.selectModel(modelId);
this.props.setModelSelected(true);
console.log('test')
console.log('modelId',modelId)
};
return(
<div>
{this.props.models.length === 1 && this.props.models.map(model => onModelSelect(model.id))}
</div>
)
}
}

Related

Why isn't setTimeout working when I persist the event that I'm using?

Here is my parent component
ReactDOM.render(
<div>
<CoordinatesButton onReceiveCoordinates={ mouseCoordinates => console.log(mouseCoordinates) } />
<DelayedButton onDelayedClick={ event => console.log(event) } delay={1500} />
</div>,
document.getElementById('global')
Now I have two child components. DelayedButton
export default class DelayedButton extends React.Component {
handleClick = (e) => {
e.persist()
setTimeout(this.props.onDelayedClick(e), this.props.delay)
};
render() {
return (
<button onClick={this.handleClick}>
DelayedButton
</button>
);
};
};
and CoordinatesButton
export default class CoordinatesButton extends React.Component {
handleClick = (event) => {
this.props.onReceiveCoordinates([event.clientX, event.clientY])
};
render() {
return (
<button onClick={this.handleClick}>
CoordinatesButton
</button>
);
};
};
Only CoordinatesButton works.
The props for onDelayedClickreturns an error of Callback must be a function. Received undefined. onDelayedClick={ event => console.log(event) } is clearly an function, because when I console log it, it logs
onDelayedClick(event) {
return console.log(event);
}
Why is this, and what can I do to fix this?
setTimeout expects a function as its first argument (read the docs [1]). You are calling your function this.props.onDelayedClick in-place, which returns undefined, hence you are receiving an error Callback must be a function. Received undefined..
Wrap the this.props.onDelayedClick(e) call in a function:
setTimeout(() => this.props.onDelayedClick(e), this.props.delay)
[1] https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout

React overwrite component function

I'm trying to do the following, currently I have 3 components:
Parent.js:
class Parent extends Component {
applyFilters = () => {console.log("applying original filters")}
setApplyFilters = (callback) => {
this.applyFilters = () => callback();
}
render(){
return(
<div>
<Filters applyFilters={this.applyFilters} />
<Screen1 setApplyFilters={this.setApplyFilters} />
</div>
)
}
}
Filters.js:
class Filters extends Component {
onButtonPress = () => {
this.props.applyFilters(),
}
render(){
...
}
}
Screen1.js:
class Screen1 extends Component {
applyFilter = () => {
console.log("Applying filters using the callback function in Screen1");
}
componentDidMount = () => {
this.props.setApplyFilters(() => this.applyFilters());
}
render(){
...
}
}
I have a Filters component that is common to all the screens. I have multiple screens of the type Screen1.
I want to on componentDidMount of the current screen pass the applyFilter function as a callback to the parent, and from the parent pass the applyFilter as a prop to the Filter component. When the onButtonPressed handler of the filter is called, it should execute the applyFilter callback for the mounted screen.
But for some reason it just prints to the console "applying original filters" which is the original string, as if the function is not being overwritten with the callback from the screen.
How do I do this correctly?
The this.applyFilters is resolved early during the render process to () => {console.log("applying original filters")}
<Filters applyFilters={this.applyFilters} />
In this scenario you only care for its value at the time that the function it references is invoked, so you want to set it lazily.
<Filters applyFilters={() => this.applyFilters()} />
This way when applyFilters invoked in Filters component, the value that is referenced in this.applyFilters is resolved and then invoked.
After changing applyFilters on the parent, rerender it i.e. with forceUpdate to make Filter component receive the changed function.
class Parent extends Component {
applyFilters = () => {console.log("applying original filters")}
setApplyFilters = (callback) => {
this.applyFilters = () => callback();
this.forceUpdate();
}
render(){
return(
<div>
<Filters applyFilters={this.applyFilters} />
<Screen1 setApplyFilters={this.setApplyFilters} />
</div>
)
}
}

call child function from parent in react 16

After upgrading to react 16 I am getting null in console.log(this.child)
My parent component
import EditReview from './partials/editReview'
class VenueDetails extends Component {
constructor(props) {
super(props)
this.child = React.createRef();
}
editButtonClick = () => {
console.log(this.child)
this.child.current.onEditClick()
}
render() {
return (
<div>
<button className="pull-right" onClick={() => this.editButtonClick(review, i)}>edit</button>
<div className="place-review-text">
<EditReview {...this.props}/>
</div>
</div>
)
}
}
My child component
class EditReview extends Component {
onEditClick(review, editIndex) {
console.log('ppp')
}
render() {
return ()
}
}
export default EditReview
I need to call onEditClick from the parent component. I tried this but doesn't work.
Kindly help me
You have to assign the ref:
<EditReview {...this.props} ref={this.child} />
Also, you don't need to use inline arrow function:
onClick={() => this.editButtonClick(review, i)}
// ------^^^^^ not required
// because, you're already using public class method
Just use:
onClick={this.editButtonClick(review, i)}
Define your method like this:
editButtonClick = (review, index) => { // to access review, i

Render a component from another class using function

So, I have a class like this:
class Blah extends Component {
constructor(props) {
super(props);
}
handleComponent = (event) => {
let divid = event.target.getAttribute('id');
if (divid === 'col') {
// I want to render component by this condition
} else if (divid === 'ro') {
// or I want to render component by this condition
} else {
//or I want to render component by this condition
}
};
render() {
const { classes } = this.props;
return (
<div>
<div id = 'col' onClick={this.handleComponent}>Sheep</div>
<div id = 'ro' onClick={this.handleComponent}>Cow</div>
<div id = 'ball' onClick={this.handleComponent}>Dog</div>
{ I want to render my component here after click }
</div>
);
}
}
I have another class written on top of this:
class Flow extends Component {
constructor(props){
super(props);
};
render() {
return(
<div style={{background:'somecolor'...blah blah}}>Clap</div>
);
}
}
And I am Passing this by:
var foo = withStyles(styles)(Flow)
I have tried returning components but I am not getting anywhere.
I can use ternary operator but it still will render only one of two but I have three component have three design for each of them.
I want to render one of them to render on some condition as stated above.
If I use states that for toggle that will too have two components for render. Don't go on the code, this is made up, So any Ideas ? Fragments ? Any help will be appreciated. Thank you.
To render component by condition simply use switch statement.
In my example we use state to store current active component.
renderMyComponent method takes care of rendering one of three possible components.
handleChange method changes current state and triggers new render of App component.
This example use class properties plugin.
renderMyComponent = () => {
means autobind and is the same as using in constuctor method
this.renderMyComponent = this.renderMyComponent.bind(this);
Working example:
const ComponentOne = () => <div>Hi, i am component one</div>;
const ComponentTwo = () => <div>Hi, i am component two</div>;
const ComponentThree = () => <div>Hi, i am component three</div>;
class App extends React.Component {
state = { current: 0 }
renderMyComponent = () => {
// Our switch conditional render
switch(this.state.current) {
case 0:
return <ComponentOne />;
case 1:
return <ComponentTwo />;
case 2:
return <ComponentThree />;
default:
return null;
}
}
handleChange = (event) => {
// We are looking for data-trigger attribute
// In this example we expect type number but trigger holds string
// That's why we 'cast' to a number using Number()
const current = Number(event.target.dataset.trigger);
// Sets new state of current component and triggers new render
this.setState({ current })
}
render() {
return (
<div>
<div>
Pick component to render
<button
type="button"
data-trigger="0"
onClick={this.handleChange}
>
Render 1
</button>
<button
type="button"
data-trigger="1"
onClick={this.handleChange}
>
Render 2
</button>
<button
type="button"
data-trigger="2"
onClick={this.handleChange}
>
Render 3
</button>
</div>
{this.renderMyComponent()}
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Reviewing your code:
You don't need constructor here.
...
constructor(props){
super(props);
}
...

React HandleDelete TypeError undefined

I have React component called Websites to handle state
class Websites extends React.Component {
constructor(props) {
super(props);
this.handleWebsiteDelete = this.handleWebsiteDelete.bind(this);
this.state = {
websites: this.props.websites
}
}
handleWebsiteDelete(id) {
console.log("delete")
// How to Run This Function?
// ...further code to delete id from state.websites
}
render () {
return(
<div className="row">
{
this.state.websites.map(function(website, index) {
return (
<WebsiteItem key={website.id} {...website} onDelete={this.handleWebsiteDelete}/>
)
})
}
</div>
);
}
}
Then I have React component called WebsiteItem with a function handleDelete an object:
class WebsiteItem extends React.Component {
handleDelete(e) {
e.preventDefault();
$.ajax({
method: "DELETE",
url: "/websites/" + this.props.id
})
.done(function(){
this.props.onDelete(this.props.id);
}.bind(this))
}
render() {
return (
<div className="card">
{this.props.name}
<a href="#" onClick={this.handleDelete.bind(this)}>Delete</a>
</div>
);
}
}
My goal is to delete a website from a server using ajax inside WebsiteItem component (successfully done) and run a function onDelete inside Websites component to update the state this.state.websites.
I can't manage to run the function with an error: Uncaught TypeError: this.props.onDelete is not a function - I tried to play with bind(this) but not sure if I complete understand it. Thank you.
You almost got it right.
You have to bind the callback function you are passing to this.state.websites.map() to your component instance.
In order to do it, you have to pass the context as the second argument to .map()
{
this.state.websites.map(function(website, index) {
return (
<WebsiteItem key={website.id} {...website} onDelete={this.handleWebsiteDelete}/>
)
},this)
}
Or use arrow functions
{
this.state.websites.map((website, index) => {
return (
<WebsiteItem key={website.id} {...website} onDelete={this.handleWebsiteDelete}/>
)
})
}

Categories

Resources