Reputation: 103
I have a scenario where I'm using React.js to create a div using the following code :
React.createElement('div', {}, "div content")
Some additional javascript processing will allow me afterwards to deduce if this div needs to have the className attribute set to" ClassA" or "ClassB" or if it shouldn't have className at all.
Is there a way in javascript to access the div that was created from the React DOM and to add to it the className attribute?
Note : I couldn't achieve this is JSX so I resorted to the createElement method.
Edit: it is worth to mention that i might need to conditionally add attributes other than className. For example, I might need to add to an anchor tag an "alt" attribute or not based on conditional logic. Thank you in advance.
Upvotes: 7
Views: 11845
Reputation: 2025
You can use ES6 syntax to achieve the desired functionality
const yourComponentProps = {
[ifThisIsTrue ? 'useThisName' : 'useAnotherName']: 'yourDesiredValue',
};
return <YourComponent {...yourComponentProps} />
Upvotes: 0
Reputation: 546
Use JSX spread. Build and object with props, modify it however you like and pass it to component like so:
const props = {
name: 'SomeName'
}
if (true) {
props.otherName = 'otherName';
}
return (
<SomeComponent {...props}/>
);
See that ...
syntax? That spread operator do the job - all props will end up as separate attributes on your component.
Take a look at this plunk: http://www.webpackbin.com/4JzKuJ9C-
Upvotes: 7
Reputation: 281686
Since you were trying to initially have your logic in JSX. I have a jsx solution that uses state
class App extends React.Component {
constructor() {
super();
this.state = {
classValue: ''
}
}
handleClick = () => {
if(this.state.classValue == '') {
this.setState({classValue : 'green'});
}
else if(this.state.classValue == 'green') {
this.setState({classValue : 'blue'});
}
else {
this.setState({classValue : 'green'});
}
}
render() {
return (
<div>
<div className={this.state.classValue}>Hello World</div>
<button onClick={this.handleClick()}>Toggle</button>
</div>
)}
}
ReactDOM.render(<App/>, document.getElementById('app'));
.green {
background-color: green;
}
.blue {
background-color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>
<div id="app"></div>
The example shows how can you change your className similarly using state you can set whatever attributes you like to change.
Upvotes: 0
Reputation: 17956
This is a quite normal situation in React and requires virtually no special handling.
Note: It is best to hand props down the component tree declaratively but if that is not an option you can bind listener functions in componentDidMount
and unbind them in componentWillUnmount
as shown in the following example. So long as they call setState, your component's render function will get triggered.
const { Component, cloneElement } = React
class Container extends Component {
constructor(props) {
super(props)
this.state = { classNames: [ 'foo' ] }
this.appendClassName = () => {
const { classNames } = this.state
this.setState({ classNames: [ ...classNames, `foo_${classNames.length}` ] })
}
}
componentDidMount() {
document.querySelector('button').addEventListener('click', this.appendClassName)
}
componentWillUnmount() {
document.querySelector('button').removeEventListener('click', this.appendClassName)
}
render() {
const { children } = this.props
const { classNames } = this.state
return <div className={classNames.join(' ')}>{children}</div>
}
}
ReactDOM.render(<Container>I am content</Container>, document.getElementById('root'))
.foo {
font-family: monospace;
border: 1px solid rgb(100, 50, 50);
font-size: 1rem;
border-style: solid;
border-width: 1px;
width: 50vw;
height: 50vh;
margin: auto;
display: flex;
align-self: center;
justify-content: center;
align-items: center;
}
.foo.foo_1 {
font-size: 1.5rem;
background-color: rgb(200, 100, 200);
}
.foo.foo_2 {
font-size: 2rem;
border-radius: 3px 7px;
background-color: rgb(180, 120, 200);
}
.foo.foo_3 {
border-style: dashed;
background-color: rgb(175, 130, 180);
}
.foo.foo_4 {
border-width: 2px;
background-color: rgb(160, 165, 170);
}
.foo.foo_5 {
border-width: 1rem;
background-color: rgb(150, 200, 150);
}
<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>
<button>Click me</button>
<div id="root"></div>
P.S. - Avoid using componentWillMount
, it can lead to bugs in the lifecycle and there is talk that it may be removed in a future version of React. Always make async side-effect laden requests within componentDidMount
and clean them up in componentWillUnmount
. Even if you have nothing to render, you are best off rendering a placeholder component until your data arrives (best option for fast loading), or nothing at all.
Upvotes: -1