Required prop `onClick` was not specified // Cannot read property 'bind' - javascript

I'm trying to pass the 'handleWordClick' function to a component but I keep getting the error that the proptype was not specified. Also when I try to pass the prop with .bind
'this.handleWordClick.bind(this)'
...I get the error that cannot read property 'bind'.
This error maybe due to my lack of knowledge but would appreciate some help.
Thanks.
Here's the part of the code of the container:
handleWordClick: function () {
this.setState({ isModalOpen: true });
},
handleCloseModalClick: function () {
this.setState({ isModalOpen: false });
},
renderBookPage: function(which) {
var book = this.state.book;
return book[which].map(function (page, index) {
return <WordWrapper
key={index}
page={page}
onClick={this.handleWordClick} />
})
},
Here is the component that I'm trying to pass the 'onClick' prop:
function WordWrapper (props) {
return (
<span style={styles.cursorPointer} onClick={props.onClick}>{props.page.word}</span>
)
}
WordWrapper.propTypes = {
page: PropTypes.shape({
word: PropTypes.string.isRequired
}),
onClick: PropTypes.func.isRequired
}
module.exports = WordWrapper;

Try this
var _this = this;
return book[which].map(function (page, index) {
return <WordWrapper
key={index}
page={page}
onClick={_this.handleWordClick} />
})
The reason for the error is, the this inside .map() refers to the map() not the React.createClass()

Related

Vue JS - Rendering getter before template

I'm getting TypeError "Cannot read property 'email' of undefined" because it seems that the template is rendering before the getter returns the value. The value is indeed undefined as it is initialised as undefined in the store. But after the template renders, that value does return something. Is there anyway I can have my getter render after the template?
my code:
<template>
<div>
<Success :title="'title name'"
:subtitle="`your email is ${schoolDetails.email}.`"
:button-text="'button text'"
:button-link="ROUTE_NAMES_HK_ADMIN.SCHOOL_DETAILS"/>
</div>
</template>
<script>
import {ROUTE_NAMES_HK_ADMIN} from "#/router/modules/hkAdmin";
import Success from "#/components/partials/Success";
import {GET_SCHOOL_BY_ID} from "#/store/manager/actions";
export default {
name: "SchoolCreateSuccess",
components: {Success},
data: () => ({
ROUTE_NAMES_HK_ADMIN
}),
computed: {
schoolDetails: function () {
return this.$store.getters.getSelectedSchool;
},
},
methods: {
getSchoolDetails: function (schoolId) {
this.$store.dispatch(GET_SCHOOL_BY_ID, schoolId);
}
},
created() {
this.getSchoolDetails(this.$route.params.id);
}
}
How about initializing the schoolDetails variable with dummy value to fulfil the error?
Then maybe you can use watch instead of computed to align tracking the schoolDetails variable with the stored data.
So, maybe something like this:
data: () => ({
ROUTE_NAMES_HK_ADMIN,
schoolDetails: {email: ''}
}),
// note: 'watch' track changes (no changes == the function will not be called)
watch: {
// watch the state, not the getter
'$store.state.selectedSchool': () => {
this.schoolDetails = this.$store.getters.getSelectedSchool;
return;
}
}

React pass date as props : "undefined is not iterable"

I am a noob in React.
I am trying to get a variable that comes from another component.
this is in a js file for the MapLeaflet component
const date = props => {
return (
props.date);
};
And the first component (the one where the variable is date is created) is :
import React, { Component } from 'react';
import DateTimePicker from 'react-datetime-picker';
import MapLeaflets from './MapLeaflet';
class Picker extends Component {
state = {
date: new Date(),
}
onChange = date => this.setState({ date },
function(){
console.log("this works: " + this.state.date);
//const DateContext = React.createContext(this.state.date);
const DateContext =this.state.date
})
render() {
return (
<div>
<DateTimePicker
onChange={this.onChange}
value={this.state.date}
/>
{ console.log(this.state.date) }
<MapLeaflets date = {this.state.date}
/>
)}
</div>
);
}
}
export default Picker;
Here is my log error :
TypeError: undefined is not iterable (cannot read property
Symbol(Symbol.iterator))
I have extensively searched stackoverflow. This appears to be a pretty simple problem, yet it does not work here. I can read use child/parents, or context, but i did not manage to make it work. I did not try redux, but i guess this would be overkill to just pass a props.
Any observation or suggestion would be valuated.
EDIT
Thanks for your answer. Actually the error log comes from this line in the first component :
<MapLeaflets date = {this.state.date}
/>
Does anybody knows why it does not work ?
I am editing also to include a part of the mapleaflet component, just so you understand what i want to do with this date.
refreshStationsList() {
const { updateFavStationsList, readStoredFav } = this.props;
// console.log('refresh');
const date = (props) => {
return (
<div>{props.date}</div>
)
}
const request = `https:url`+date;
this.setState({ isLoading: true });
const favStationsId = readStoredFav();
axios.get(request)
.then(result => {
const stationsList = result.data.map(
station => {
const isFavorite = favStationsId.includes(station.number);
return { ...station, isFavorite: isFavorite }
}
);
this.setState({
stationsList: stationsList,
isLoading: false
})
updateFavStationsList(stationsList);
})
.catch(error => this.setState({
apiDataError: error,
isLoading: false
}));
}
render() { ....etc
Your MapLeaflets component should look like this
const MapLeaflets = (props) => {
return (
<div>{props.date}</div>
)
}
export default MapLeaflets;
You are trying to loop on undefined, first make sure that you are getting data from your api. and always try to do type check before proceeding.
You can use typeof to do type check

React Classes: Referencing class as "this", within an object's function property

I have finally gotten into using react and ES6 and it's going well but I am finally stumped and could use some direction.
I have got my head around binding this to a method to reference the class, but I am trying to go a bit deeper. Take this for example...which works as expected:
class App extends Component {
state = {
myFirstState: false,
};
handleMyFirstState = () => {
this.setState( { myFirstState : true } );
};
render() {
return (
<MyComponent handleMySate={ this.handleMyState } />
);
}
}
export default App;
As the amount of methods increased I decided NOT to pass each method individually as props and to group them in an object first, and to just pass the object as a whole, as a prop. Like So...
class App extends Component {
state = {
myFirstState: false,
mySecondState: false
};
handleMyFirstState = () => {
this.setState( { myFirstState : true } );
};
handleMySecondSate = () => {
this.setState( { mySecondState : true } );
};
render() {
const handleStates = {
first : this.handleMyFirstState,
second : this.handleMySecondState
}
return (
<MyComponent handleStates={ handleStates } />
);
}
}
export default App;
Now, I am trying to avoid redundant code and just build the methods as one object with functions as properties before the render begins. Pretty much like this...
class App extends Component {
state = {
myFirstState: false,
mySecondState: false
};
handleStates = {
// Here is where 'this' does not reference the App class
// I get results from the console log but setstate doesn't pass correctly
first : () => { console.log("First Triggered"); this.setState( { myFirstState : true } ); },
second : () => { console.log("Second Triggered"); this.setState( { mySecondState : true } ); }
};
render() {
return (
<MyComponent handleStates={this.handleStates} />
);
}
}
export default App;
// I trigger the function like this within MyComponent and I get the console log, but `this.setState` breaks.
<Button onClick={ this.props.handleState.first } >Handle First</button>
I have successfully triggered the functions from the child component ,<MyComponent/>, using the latter code, but this no longer refers to the class and I can't figure out how to bind this to handleStates since it's not a function.
Is this just not possible or is there another way to handle what I am trying to achieve?
Thank you in advance!
ADDITIONAL
If I move the handleStates into the render() it works just fine...how could that be?
class App extends Component {
state = {
myFirstState: false,
mySecondState: false
};
render() {
const handleStates = {
first : () => { this.setState( { myFirstState : true } ); },
second : () => { this.setState( { mySecondState : true } ); }
};
return (
<MyComponent handleStates={this.handleStates} />
);
}
}
export default App;
First, in the second example, you pass this.handleStates as the value for the prop handleStates, but it's undefined. You built handleStates as a local variable, and thus you want your props to reference that local variable:
<MyComponent handleStates={handleStates} />
For your third (last) example, your issue is even simpler: you defined handleStates as an attribute on this which is assigned an object, itself with two attributes, first and second, each of which have a function as their value.
When you ultimately pass this.handleStates to MyComponent, you're passing an object, not a function. If you want to call one of first or second from MyComponent, you can do so like this:
this.props.handleStates.first()
Which has the desired result of updating the state in App.
For what it's worth, there's a more common pattern for this: simply pass a single updater function as the prop, named according to what it does:
class Sandwich extends React.Component {
this.state = {
bread: "",
meat: "",
veggie: "",
}
updateSandwich = (component, selection) => {
this.setState({ [component]: selection })
}
render() {
return(<IngredientSelector updateSandwich={this.updateSandwich} />)
}
}
class IngredientSelector extends React.Component {
return(){
<button value="Rye" onClick={() => this.updateSandwich("bread", "rye")} />
<button value="Wheat" onClick={() => this.updateSandwich("bread", "wheat")} />
<button value="Ham" onClick={() => this.updateSandwich("meat", "ham")} />
<button value="Turkey" onClick={() => this.updateSandwich("meat", "turkey")} />
}
}

React show component based on variable value

Learning React & chrome extensions the hard way, so my this.url has one of 2 values:
null or www.sample.com
I'm getting the url value from an async call using chrome.storage.local.get(...) so once I get the response from the storage I set the value to this.url and want to use such value to display a component using a ternary operator like so:
export default React.createClass({
url: '',
componentDidMount: function(){
this.observeResource();
},
observeResource(){
var self = this
function getValue(callback){
chrome.storage.local.get('xxxx', callback);
}
getValue(function (url) {
this.url = url.xxxx;
return this.url;
});
},
/* RENDER */
render: function(){
return (
<div className="app">
<AppHeader />
{this.url != null ?
<VideoFoundOverlay />
: null}
{this.url == null ?
<VideoNotFoundOverlay />
: null }
</div>
)
}
});
I can not get the value of this.url outside of the observeResource function. Where am I going wrong?
You need to use this.setState()
constructor(props) {
super(props)
this.state = {
url: ''
}
}
componentDidMount() {
setTimeout(() => {
this.setState({ url: 'www.sample.com' })
}, 1000)
}
render() {
return <div>this.state.url</div>
}
Look at working example in JSFiddle
The this inside the following call points to window rather than the component itself, since the callback is invocated as a function, the window is actually the "owner" of the function.
getValue(function (url) {
this.url = url.newswireStoryUrl;
return this.url;
});
To avoid this error, you could use self.url instead, since you have explicitly assign this to self. Or you could use Arrow Function instead of function(...).
To render the component, you should declare url as a state, because only state changes will cause the render function to be called.
export default React.createClass({
getInitialState: function() {
return { url: '' };
},
componentDidMount: function(){
this.observeResource();
},
observeResource(){
var self = this;
function getValue(callback){
chrome.storage.local.get('newswireStoryUrl', callback);
}
getValue(function (url) {
self.setState({ url: url.newswireStoryUrl });
return self.state.url;
});
},
/* RENDER */
render: function(){
return (
<div className="app">
<AppHeader />
{this.state.url !== null ?
<VideoFoundOverlay />
: null}
{this.state.url === null ?
<VideoNotFoundOverlay />
: null }
</div>
);
}
});
I would go by and do it like this:
export default React.createClass({
getInitialState: function(){
return {
url: null
}
},
componentDidMount: function(){
this.observeResource();
},
observeResource(){
var self = this
function getValue(callback){
chrome.storage.local.get('newswireStoryUrl', callback);
}
getValue(function (url) {
//here you are seting the state of the react component using the 'self' object
self.setState({url: url.newswireStoryUrl})
//not sure if the 'return this.url' is needed here.
//here the 'this' object is not refering to the react component but
//the window object.
return this.url;
});
},
videoNotFound: function(){
return (
<div className="app">
<AppHeader />
<VideoNotFoundOverlay />
</div
)
},
/* RENDER */
render: function(){
if(this.state.url == null){
return this.videoNotFound()
}
return (
<div className="app">
<AppHeader />
<VideoFoundOverlay />
</div>
)
}
});

Props not setting state

I have a react component that gets a prop from another parent component. I checked in react developer tools, and the prop is for sure getting passed.
Here is my code:
var Post = React.createClass({
getInitialState: function () {
return { content: this.props.content };
},
rawMarkup: function() {
var rawMarkup = marked(this.state.content, {sanitize: true});
return { __html: rawMarkup };
},
render: function() {
return (
<div>
{this.props.content }
<div dangerouslySetInnerHTML={ this.rawMarkup() } />
</div>
);
}
});
This results in the error: Uncaught TypeError: Cannot read property 'replace' of undefined for marked.js. However, when I setInitialState to return { content: "Blah" }; it works fine. So it looks like the prop is not set there?
But when I do the {this.props.content} in the render, it works fine?
It's just that your state is out of date. Try adding this:
getInitialState: function () {
return { content: this.props.content || '' };
},
componentWillReceiveProps: function(nextProps) {
if (this.props.content !== nextProps.content) {
this.setState({
content: nextProps.content || '',
});
}
},
Read more about components' lifecycle here.
Edit: This will solve your problem, but generally using state this way is an anti-pattern (unless content is an input or something, you haven't mentioned that in your question). What you should do instead is create a new component that will only accept content prop and render marked output. I suggest you use a stateless functional component here.
var MarkedContent = (props) => {
return <div dangerouslySetInnerHTML={{__html: marked(props.content || '', {sanitize: true})}}></div>
}
Drop this component inside your Post component like this:
var Post = React.createClass({
render: function() {
return (
<div>
<MarkedContent content={this.props.content} />
</div>
);
}
});
Thanks David Walsh!
You don't have to synchronize props with state, even more using props in state is anti-pattern. render() is called each time when props or state changed
However, it's not an anti-pattern if you make it clear that
synchronization's not the goal here
var Post = React.createClass({
rawMarkup: function() {
var rawMarkup = marked(this.props.content, {sanitize: true});
return { __html: rawMarkup };
},
render: function() {
return (
<div>
{this.props.content }
<div dangerouslySetInnerHTML={ this.rawMarkup() } />
</div>
);
}
});
Do all your Post's have content?
I guess you are getting the list of posts from somewhere (a database) and for some of them the content is undefined, hence the:
Uncaught TypeError: Cannot read property 'replace' of undefined
Probably this.props.content has undefined as value. Then, this.state.content is initialized to undefined and when you call marked(this.state.content, {sanitize: true}) you get this error because you are passing an undefined to marked.

Categories

Resources