How to pass generated HTML to the render function in JSX? - javascript

Is it a legit way to pass generated HTML in the render function of the component in JSX?
...
//get variables elsewhere
const input = <input type={inputType} ... />
return (
{input}
)
...
When I've tried to build it as a string, e.g. const input = '<input type="' + inputType'" + />' it was rendered as a plain text.
Actually, my return is:
return (
<div>{input}</div>
)

The code you've posted is perfectly fine other than the return (we'll get to that in a moment); you don't need or want to use a string instead.
Remember that JSX is just syntactic sugar for JavaScript code:
const input = <input type={inputType} />;
...is just a sugared version of React.createElement:
const input = React.createElement("input", { type: inputType });
It creates the element object, which you can certainly pass around between functions, and which you can render by returning it from render.
To do that return, you want simply:
return input;
Your return ({input}) won't work because you're trying to use the JSX syntax for inserting a JavaScript expression ({...}) outside JSX.
Live Example:
class Example extends React.Component {
getTheThing() {
const inputType = "text";
const input = <input type={inputType} />;
return input;
}
render() {
const input = this.getTheThing();
return input;
}
}
ReactDOM.render(
<Example />,
document.getElementById("root")
);
<div id="root"></div>
<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>
Re your edit:
Actually, my return is:
return (
<div>{input}</div>
)
That's fine (other than the missing ; — I don't care for relying on ASI), because you're using {...} in a JSX block (<div>...</div>).
Live Example:
class Example extends React.Component {
getTheThing() {
const inputType = "text";
const input = <input type={inputType} />;
return input;
}
render() {
const input = this.getTheThing();
return (
<div>{input}</div>
);
}
}
ReactDOM.render(
<Example />,
document.getElementById("root")
);
<div id="root"></div>
<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>

Related

array.map() is returning elements all together in React JS

const test = () = {
const array = ['hello', 'myNameIs']
return (
{
array.map((arr) => (
<div>{arr}</div>
<button>Edit</button>
)
}
)
}
This .map() method is not working as I intended.
With the code, I was trying to get
hello [button]
myNameIs [button]
like this.
But when I actually render the code, I get
hello MynameIs [button]
In this kind of situation, How can I change the .map() statement?
Should I use an index?
Take a look at below example, I created it almost by your code, it is working as you expected without problem.
function App() {
const array = ['hello', 'myNameIs'];
return array.map(item => (
<div key={item}>
{item} <button>Edit</button>
</div>
));
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
You are not using the correct syntax for the arrow function
It should be like
const test = ()=>{}
React component JSX should return one parent container try wrapping it like:
const Test = () => {
const array = ["hello", "myNameIs"];
return (
<>
{array.map((arr) => {
return (
<>
<div>{arr}</div>
<button>Edit</button>
</>
);
})}
</>
)
}
Here is the working code sandbox link https://codesandbox.io/s/kind-easley-jxiei?file=/src/App.js:57-336
I Hope it helps.
Create the button inside the div tag. Also you can use style to align the items as required
array.map((arr) => (
<div>{arr} <button>Edit</button></div>
)
const test = () = {
const array = ['hello', 'myNameIs']
return (
{array.map((item,key) => (
<div key={item}>{item}</div><button>Edit</button>
)})
}

React interract with dom

How can I 'talk' with dom elements with react?
For example - I need to bind some actions with some js lib
Both approaches returns undefined for some reason
componentDidMount() {
const element1 = document.querySelector('.home-container')
const element2 = ReactDOM.findDOMNode(this);
// returns undefined, undefined
console.log(element1.length, element2.length);
}
render() {
return (
<div className="home-container">
...
</div>
)
}
But console.log(element1) returns html from render itself though
How can I work with them?
And what correct lifecycle method for this?
You use "refs":
<div ref={e => {this.div = el}} ...>...</div>
Once your component has rendered, with the above, its div property (you can use any name you want) will refer to the div element that was rendered.
Here's an example largely copied from the link above that focuses a text input when it's rendered:
class AutoFocusTextInput extends React.Component {
componentDidMount() {
this.textInput.focus();
}
render() {
return (
<input type="text"
ref={(input) => { this.textInput = input; }} />
);
}
}
ReactDOM.render(
<AutoFocusTextInput />,
document.getElementById("root")
);
<div id="root"></div>
<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>

How to extract JSX from class render method?

I want to write something like SCSS for React Native: it'll parse your component jsx and the special SCSS-like styles and return a usual RN component with reworked styles and jsx.
Lets say we have this react code:
class MyClass extends Component {
render() {
return (
<View style={styles.container}>
<Text>I remember syrup sandwiches</Text>
</View>
);
}
}
Also I have SCSS-ish styles where every Text component inside the parent with a container "class" will have the same props that we provided.
const styles = StyleSheet.create(
toRNStyles({
container: {
Text: { color: 'red' },
},
})
);
In the end we need the output of something like this:
...
<View style={styles.container}>
<Text style={styles._Text_container}>
I remember syrup sandwiches
</Text>
</View>
...
So how can I get the jsx that's returning from the render method from outside the class?
You might write a plugin for babel, as react-native uses it to transform JSX to plain javascript.
Have a look to the these packages:
babel-helper-builder-react-jsx
babel-plugin-syntax-jsx
babel-plugin-transform-react-jsx
babel-plugin-transform-react-jsx-source
jsx-ast-utils
There doesn't seem to be a standard way of doing this. However, you could import ReactDOMServer and use its renderToStaticMarkup function.
Like this:
class MyApp extends React.Component {
render() {
var myTestComponent = <Test>bar</Test>;
console.dir(ReactDOMServer.renderToStaticMarkup(myTestComponent));
return myTestComponent;
}
}
const Test = (props) => {
return (
<div>
<p>foo</p>
<span>{props.children}</span>
</div>
);
}
ReactDOM.render(<MyApp />, document.getElementById("myApp"));
<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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom-server.js"></script>
<div id="myApp"></div>
I think parsing the returned element is the wrong approach. One challenge will be that the value of style will be an object (styles.container === a hash of style key/values) whereas you need a key which can be mapped to the object.
I think the most reusable approach is to leverage React context (which I'm assuming RN supports!) to build a styleName which can be augmented as you got down the component tree.
Here's an initial approach which makes a few assumptions (e.g. that every component will have styleName provided as a prop; you might want to provide that at design-time rather than run-time). In short, you wrap every component you want to participate with this HOC and the provide styleName as a prop to each component. Those styleName values are concatenated to produce contextualized names which are mapped to styles.
This example produces:
<div style="background-color: green; color: red;">
<div style="color: blue;">Some Text</div>
</div>
const CascadingStyle = (styles, Wrapped) => class extends React.Component {
static displayName = 'CascadingStyle';
static contextTypes = {
styleName: React.PropTypes.string
}
static childContextTypes = {
styleName: React.PropTypes.string
}
// pass the current styleName down the component tree
// to other instances of CascadingStyle
getChildContext () {
return {
styleName: this.getStyleName()
};
}
// generate the current style name by either using the
// value from context, joining the context value with
// the current value, or using the current value (in
// that order).
getStyleName () {
const {styleName: contextStyleName} = this.context;
const {styleName: propsStyleName} = this.props;
let styleName = contextStyleName;
if (propsStyleName && contextStyleName) {
styleName = `${contextStyleName}_${propsStyleName}`;
} else if (propsStyleName) {
styleName = propsStyleName;
}
return styleName;
}
// if the component has styleName, find that style object and merge it with other run-time styles
getStyle () {
if (this.props.styleName) {
return Object.assign({}, styles[this.getStyleName()], this.props.styles);
}
return this.props.styles;
}
render () {
return (
<Wrapped {...this.props} style={this.getStyle()} />
);
}
};
const myStyles = {
container: {backgroundColor: 'green', color: 'red'},
container_text: {color: 'blue'}
};
const Container = CascadingStyle(myStyles, (props) => {
return (
<div {...props} />
);
});
const Text = CascadingStyle(myStyles, (props) => {
return (
<div {...props} />
);
});
const Component = () => {
return (
<Container styleName="container">
<Text styleName="text">Some Text</Text>
</Container>
);
};
<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>

React - Instance creation and usage of a class

I'm trying to get an instance of the class ActionEditor So that I'd be able to use its methods later:
function render() {
const toRender = responseActions.map((actionInstance) => {
currentActionEditing=actionInstance;
return <li>{ actionInstance === expandedAction ? <ActionEditor id={actionInstance.title} action={getActionByKey(actionInstance.actionType)} instance={actionInstance} state={actionInstance} /> : <button onClick={createOnClick(actionInstance)}>{actionInstance.title}</button>}</li>;
});
ReactDOM.render(
<div>
<div>{toRender}</div>
<button style={styleButtonGenerate} onClick={onGenerateClick}>Generate</button>
</div>,
document.getElementById('root')
);
}
I've attempted to use it through an onClick method like so:
function onGenerateClick() {
var editor = document.getElementById(currentActionEditing.title);
editor.prototype = ActionEditor;
editor.methodIWantToUse();
}
But it always turns out to be null/undefined.
I understand that it's not the best example but it should be enough to demonstrate the issue.
Is there a way around this?
I think what you want here is to save a ref to the component so it can be accessed, see in the example below how the sayHi method is called from the parent component.
class MyComponent extends React.Component {
sayHi() {
console.log('hi');
}
render() {
return (<div>I'm a component!</div>)
}
}
class App extends React.Component {
render() {
// just a way to show how to access a child component method.
setTimeout(() => {
this.node.sayHi();
}, 1000)
return (<MyComponent ref={(node) => this.node = node}/>)
}
}
ReactDOM.render(<App />, document.querySelector("body"))
<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>

React: Pass component as prop without using this.props.children

I have this a component Foo.js:
// a svg component with a star.svg icon
import { IconStar } from 'react-svg-icons';
// call a button with a custom icon
<Button icon={ IconStar }> Click to trigger </Button>
And then on button.js I have:
render() {
const theIcon = this.props.icon;
return (
<button>
{this.props children}
{icon() /*this works but i can't pass props inside it*/}
<theIcon className={ Styles.buttonIcon } />
</button>
)
}
I want to render <IconStar> inside <Button>, how do I do that?.
I can't pass this as this.prop.children because it has more logic around the icon prop, but in this case I'm showing only a demo.
Thanks
The only thing you have missed is that for JSX to transpile to JS custom components should be named starting with a capital letter, e.g. <TheIcon />, while lowercase letter signifies native DOM elements, e.g. <button />.:
render() {
const TheIcon = this.props.icon; // note the capital first letter!
return (
<button>
{this.props.children}
<TheIcon className={ Styles.buttonIcon } />
</button>
)
}
https://jsfiddle.net/03h2swkc/3/
If your using es6 then you can use a spread operator to pass the attributes to a below component, I think that might solve your problem:
var MyIcon = (props) => {
return <i {...props}> {
props.className
} < /i>
};
var MyButton = (props) => {
return ( < button > {
props.children
}<MyIcon {...props} />< /
button > );
}
ReactDOM.render( <
MyButton className = 'my-icon'>My Button Text</MyButton> ,
document.getElementById('myComponent')
)
<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='myComponent'></div>
so the ...props will pass myProps into IconStar. Obviously you can pass anything you want through.

Categories

Resources