React JS: HTML is rendered on screen - javascript

It must be an ultra basic. I want to make a very first demo, without using JSX to be more direct.
const nicolas = {
admin: true,
id: 1,
email: "xyz#zyx.io",
name: "Nicolas",
statement: "Star Wars rocks"
};
class User extends React.Component {
render() {
return React.createElement('div', null,
`<div>name: ${this.props.name}</div>
<div>statement: ${this.props.statement}</div>`
);
}
}
ReactDOM.render(
React.createElement(User, nicolas, null),
document.querySelector('section.app')
);
As a result, div tags are shown directly. Why ? and how to avoid that ? Must I use multiple imbricated React.createElement()

Why ?
Because you are passing a string as a child to the element. The string is literally rendered into the document. It's the same as if you did:
<div>{'<span>something</span>'}</div>
in JSX, which is not the same as
<div><span>something</span></div>
How to avoid that ? Must I use multiple imbricated React.createElement()
Yes, every element needs to be created with React.createElement. There is a way to directly set HTML as content of an element, but you should avoid that.

React.createElement(root, props, elements) accept multiples elements, that can be strings.
const e = React.createElement;
class User extends React.Component {
render() {
return e('div', null,
// strong for the whole line
e('div', null,
e('strong', null, `name: ${this.props.name}`)
),
// strong for left part only
e('div', null,
e('strong', null, 'statement:'),
e('span', null, this.props.statement)
)
}
}
React.createElement Reference ;
React Without JSX

Related

Problem with acces to function with react javascript child component

They would like to function from the component from the child component. This method call: TypeError: Pizza__WEBPACK_IMPORTED_MODULE_2_.default.valid is not a function.
I try to add static function but it will not get the value.
I can add code of pizza to orders, but this not I will.
Can anyone help?
I want to get dish_details from Pizza and Show Pizza form underneath.
In .js no .tsx
Parend class:
class Orders extends React.Component {
constructor(props) {
super(props);
this.order = {
name: "",
preparation_time: "00:00:00",
type: "",
}
}
kind(){
switch (this.order.type) {
case 'pizza':
return <Pizza/>;
}
}
submit(){
console.log(Pizza.dishDetails()); // return error
}
render() {
return (<div>
<div>{this.state.selected ? this.kind() : ""}</div>
<button className={styles.order_submit} onClick={this.submit.bind(this)}>Submit</button>
</div>
);
}
Kids class:
class Pizza extends React.Component{
constructor(props) {
super(props);
this.state = {
noOfSlices : 0,
diameter : 0
}
}
dishDetails(){
return this.state;
}
noOfSlices(e){
this.setState({noOfSlices : e.target.value});
}
If you want your components to have a state you need to declare it with
this.state.[the name of the variable]
That's how react knows that you want to store state inside a component. The error you get probably is because you declared the state of the pizza component wrongly
dish_details = { //Not correct
noOfSlices : 0,
diameter : 0
}
Here you declare it inside the constructor, and that is correct, but in order to work you need to use the component state.
constructor(props) { /
super(props);
this.state.order = {
name: "",
preparation_time: "00:00:00",
type: "",
}
}
Check out the docs on state.
You have several issues here
you say something is static, but you have not created a static function!
submit(){
console.log(Pizza.dishDetails()); // return error or undefined when static
}
This is a call to a static function. To create a static function you would do this:
// ES5
Pizza.dishDetails = function(){ /* do something that does not touch `this` */ }
or in modern ES2015+:
class Pizza {
static dishDetailsfunction(){
/* do something that does not touch `this` */
}
}
The dishDetailsfunction function is not static, but more importantly, it cannot be static, since it uses this. A static function has no reference to this - that's the definition of static.
So you need to reorganize a bit ...
You are not allowed to access the inner state of a component from an outer component, so you need to either do your data and external actions handling outside of your components (like Redux), use some kind of callback logic, or delegate the logic for handling submits down to Pizza.
Here is one way to do it using a callback:
In the order component
renderPizza() {
// the `this` in the callback references the Orders (parent) component
return <Pizza onChange={(pizzaOrder) => this.setState({order: pizzaOrder}) }/>} />
}
In the pizza component:
updateNoOfSlices(e){
this.setState({noOfSlices : e.target.value});
this.prop.onChange({this.state});
}
I removed all the logic that is not necessary for the point, but you should see how a callback solves this easily.
P.S. If you centralize your data handling in one place (for instance a component) you will get simpler and more easily testable code. For instance, you can remove all state from the Pizza class and just let it have noOfSlices and diameter passed to it as props from the Orders class.
I have answer. I create clas Static with static value, and this is working for me.
static
class Static {
static defaultProps = {}
}
export default Static;
order
submit(){
console.log(Static.defaultProps)
pizza
noOfSlices(e){
Static.defaultProps = {noOfSlices : e.target.value};
}

one specific props gets undefined when component unmounts

So, this is a very weird one to me.
in my Redux store, I have to following meal:
{id: 39,
name: "Poisson à la basque",
restaurant: {
id: 3,
MID: "123456",
name: "le pré catelan"
}
}
I have a Container parent component and a child component where the parent provides props to the child.
(for simplicity purposes I won't explain here with I can't access directly the redux store from the child component. The thing is: I can't.)
class Parent extends Components {
render() {
return (
<Child
mealId={this.props.meal.id}
MID={this.props.meal.restaurant.MID}
/>
)
}
}
class Child extends Components {
render() {
return (
<div>
{this.props.MID ? (
<p>There is a MID</p>
) : (
<p>there is no MID</p>
)
}
)
}
}
Here is what happens: Parent and Child are called within a Modal component from reactstrap. When the Modal (and hence the Parent and Childcomponents) mounts, everything works great.
But when I trigger the event that should hide the Modal component (e.g. click outside the modal or on the cross on the top right corner), is get the following error:
TypeError: Cannot read property 'MID' of undefinedand it highilights the line from Parent: MID={this.props.meal.restaurant.MID}.
Notice that it only happens when I try to use any value from the restaurant object that is inside the meal object. When using values directly from the meal object, I get no error.
How is this possible ?
Do not hesitate to comment if I forgot to add any relevant information to help me solve the issue.
edit: here is the reducer:
case TOGGLE_MEAL_MODAL: {
return {
...state,
mealModalOpen: !state.mealModalOpen,
meal: action.payload.meal
}
}
where action.payload.meal is the kind of object mentionned above if the modal is to be open, and {} if the modal is to be closed.
When the modal unmounts, it changes the meal object to {}in the redux store. Hence this.props.meal.restaurant.MID won't work; unless the empty object looks like so:
{meals:
{
restaurant: {
MID: ""
}
}
}
so that it remains a valid object.

Changing Class Based on Object Properties in React

I wish to do the following in my application:
1) access the the property of color and option from each object
2) check the property
3) give a class based on that property
4) toggle the class onClick
The json object looks like this{
{
"green": false,
"other": "third",
"option" : 2
},
{
"green": false,
"other": "third",
"option": 1
},
{
"green": true,
"other": "first",
"option": 5
}
And so on...
Each object will be giving back a number for the key ([0],[1] etc).
My React code is as follows:
class Inf extends React.Component {
constructor() {
super();
this.state = {
colorData: data
}
}
renderList(data){
return(
<ul>{Object.keys(this.state.colorData).map(thing =><li>{thing}</li>)}</ul>
)
}
render() {
console.log(this.state.colorData)
return (
<div>
<div>{this.renderList(this.state.colorData)}</div>
</div>
);
}
}
ReactDOM.render(
<Inf />,
document.getElementById('root')
);
Sounds like you can make use of this library: classnames
The Usage section of the readme explains it very well, but basically you can then use it to do something like:
const classes = classNames({
classA: colorData.green,
classB: colorData.red
})
Basically the className on the left hand side will only be applied if the expression on the right hand side is true. And then you can assign the classes to the react className prop
In your renderList function, you can style the li returned by your map with className={desiredClass}.
There are two variables I'm not sure about in your question:
what key you're storing color under in the object
how you determine which class to add based on this color
I assume you use .color and then have a function classBasedOnColor to apply a class name based on this color. You could also use a dictionary with color keys and class name values.
It would look like this:
<ul>{Object.keys(this.state.colorData).map(thing=>{
const color = this.state.colorData[thing].color;
const desiredClass=classBasedOnColor(color);
return <li className={desiredClass}>{thing}</li>
})}</ul>

ReactDOM render fails when using JSX

I am using ReactDOM.render() to render a component I have created. The component is fairly complicated, due to the specifics of the implementation, but I can easily render it iff I avoid using JSX syntax. However, if I use JSX, I cannot render the component at all and I get the following error:
TypeError: _this2.props.children.forEach is not a function
My code can be seen below (I also get a few warnings that I haven't gotten around to fixing yet, so you can just ignore those for the time being). Bear in mind that the structure of the HTML for the component is very strict (due to the CSS framework I'm using) and cannot be changed. Is there a way to use JSX for achieving the same result and, if so, what is it that I'm doing wrong?
// This function was based on this answer: https://stackoverflow.com/a/10734934/1650200
function generateUniqueId() {
// always start with a letter (for DOM friendlyness)
var idstr = String.fromCharCode(Math.floor((Math.random() * 25) + 65));
do {
// between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
var ascicode = Math.floor((Math.random() * 42) + 48);
if (ascicode < 58 || ascicode > 64) {
// exclude all chars between : (58) and # (64)
idstr += String.fromCharCode(ascicode);
}
} while (idstr.length < 32);
return (idstr);
}
// Technically this is not exactly a component, but I use it as such to make things simpler.
class Tab extends React.Component {
render() {
return React.createElement('div', {}, this.props.children);
}
}
// This is my Tabs component
class Tabs extends React.Component {
// In the constructor, I take all children passed to the component
// and push them to state with the necessary changes made to them.
constructor(props) {
super(props);
var state = {
group: 'tab_group_' + generateUniqueId(),
children: []
}
this.props.children.forEach(
function(child) {
if (!child instanceof Tab) {
throw "All children of a 'Tabs' component need to be of type 'Tab'. Expected type: 'Tab' Found Type: '" + child.class + "'";
return;
}
var tab = Object.assign({}, child);
tab.internalId = 'tab_' + generateUniqueId();
state.children.push(tab);
}
);
this.state = state;
}
// When rendering, I don't render the children as needed, but I create
// the structure I need to use for the final result.
render() {
var childrenToRender = [];
var groupName = this.state.group;
this.state.children.forEach(function(tab) {
childrenToRender.push(
React.createElement(
'input', {
type: 'radio',
name: groupName,
id: tab.internalId,
checked: true,
'aria-hidden': 'true'
}
)
);
childrenToRender.push(
React.createElement(
'label', {
'htmlFor': tab.internalId,
'aria-hidden': 'true'
},
'demo-tab'
)
);
childrenToRender.push(React.createElement('div', {}, tab.props.children));
});
return React.createElement('div', {
'className': 'tabs'
}, childrenToRender);
}
}
// This works fine
ReactDOM.render(
React.createElement(Tabs, {}, [React.createElement(Tab, {}, 'Hello world')]),
document.getElementById('root')
);
// This fails with the error mentioned above
// ReactDOM.render(
// <Tabs>
// <Tab>Hello, world!</Tab>
// </Tabs>,
// document.getElementById('root')
// );
<link rel="stylesheet" href="https://gitcdn.link/repo/Chalarangelo/mini.css/master/dist/mini-default.min.css">
<script src="https://unpkg.com/react#latest/dist/react.js"></script>
<script src="https://unpkg.com/react-dom#latest/dist/react-dom.js"></script>
<script src="https://unpkg.com/babel-standalone#6.15.0/babel.min.js"></script>
<div id="root"></div>
Update: This only happens if I actually pass only one <Tab> to the <Tabs> due to the way it's processed. If, for example, I use the following code, I can use JSX to render the component and its contents:
ReactDOM.render(
<Tabs>
<Tab>Hello, world!</Tab>
<Tab>Hello, world!</Tab>
</Tabs>,
document.getElementById('root')
);
After checking out what babel output from the JSX code, I realized that it was not ouputting something like [React.createElement(Tab, {}, 'Hello world')] but rather something more like React.createElement(Tab, {}, 'Hello world'), meaning it was not an array, thus causing problems with .forEach().
To anyone interested, what I did was check if this.props.children is an array and, if not, to actually turn it into one. Sample below:
if (!Array.isArray(this.props.children))
var tempProps = [this.props.children];
else
var tempProps = this.props.children;
tempProps.forEach(
// Rest of the code is pretty much the same as before
);
This is not a very elegant solution, so feel free to post more elegant answers if you know any.

DraftJs creating simplest possible custom block

what would be the easiest way to implement custom block in Draft?
At the moment I'm using this function for default blocks
editorToggleBlockType = (blockType) => {
this.onChange(
RichUtils.toggleBlockType(
this.state.editorState,
blockType
)
);
}
then I can apply custom class using blockStyler
blockStyler = (block) => {
if (block.getType() === 'unstyled') {
return 'paragraph';
} else {
return `custom-${block.getType()}`;
}
}
Sadly blockType accepts only default types like blockquote, ol, code-block etc. and on custom type gives me an error.
Uncaught TypeError: Cannot read property 'wrapper' of undefined
My question is - how to force editor to accept custom block types so I can apply className to them? Thank you.
You need to define it in blockRenderMap.
From the docs:
const blockRenderMap = Immutable.Map({
'atomic': {
// the docs use 'MyCustomBlock', but I changed it to 'atomic' to make it easier to follow.
// element is used during paste or html conversion to auto match your component;
// it is also retained as part of this.props.children and not stripped out
element: 'section',
wrapper: <MyCustomBlock {...this.props} />
}
});
// Include 'paragraph' as a valid block and updated the unstyled element but
// keep support for other draft default block types
const extendedBlockRenderMap = Draft.DefaultDraftBlockRenderMap.merge(blockRenderMap);
class RichEditor extends React.Component {
render() {
return (
<Editor
...
blockRenderMap={extendedBlockRenderMap}
/>
);
}
}
Rather confusingly, all this does is wrap your custom block in whatever is specified in the wrapper key. The actual block is then rendered by blockRendererFn, as in the docs:
function myBlockRenderer(contentBlock) {
const type = contentBlock.getType();
if (type === 'atomic') {
return {
component: MediaComponent,
editable: false,
props: {
foo: 'bar',
},
};
}
}
// Then...
import {Editor} from 'draft-js';
class EditorWithMedia extends React.Component {
...
render() {
return <Editor ... blockRendererFn={myBlockRenderer} />;
}
}
If we follow this example verbatim, you'd get a block that looked something like:
...
<MyCustomBlock>
<MediaComponent />
</MyCustomBlock>
...
And your className from blockStyleFn would get passed to MyCustomBlock, so you can pass it down to whichever native DOM node you like. That's also why you were getting the TypeError -- DraftJS couldn't find your custom block in blockRenderMap!
I hope this answers your question. DraftJS can be confusing, but it's a very powerful framework for building RTEs.

Categories