React: modifying children
by DFID on flikr

React: modifying children

Anyone who knows me knows I hate layering on complexity made by someone else. So if I use React, I like to avoid adding yet more frameworks, modules, and libraries to it to make it do "more".

So when I was idly trying out making a monopoly game in React, I had a desire to make a form that could track the state of variables (and later incorporate error-checking code I've written before) without having to resort to Redux Form or Context or any number of solutions. It just feels superfluous like it is subverting the purpose of the original framework.

Don't get me wrong, I understand there is a point where it makes sense to use them in many circumstances. I just want to push myself to do it if I am doing something as a learning product. Using a ton of npm modules while doing a pleasure learning exercise is like going running for exercise and taking an uber halfway.

So I was trying to make my form and it was quickly turning into a rabbit hole. Everything was fine at first. I wanted to use "children" because it would be simpler to drop a pre-existing form element into the text-area of a JSX element than adding a whole object as properties.

//doing this
<Form>
  <input type="text" placeholder="enter name"/>
  <input type="checkbox" value="yes">
</Form>

//versus this

<Form contents={
  [ 
    <input type="text" placeholder="enter name"/>,
    <input type="checkbox" value="yes">
  ]
} />

Very quickly I found I wanted to do more. Obviously I have to track changes to the inputs. You don't need to directly modify the inputs themselves, because events bubble. So you COULD track changes in the parent element.

//I don't like doing this, but it is quick to display binding this way for the example
handleChange = (event) =>{
  const nameOfElement = event.target.getAttribute('name');
  const valueOfElement = event.target.value;
}
render(){
  <div onChange  ​={ this.handleChange }>
    { this.props.children }
  </div>
}

That works, but for other things, you need more. Like if you want to be able to change the value of the input, you need to be able to directly modify the input. You could go through the input via JS and modify it, but that would be ridiculous. You shouldn't modify the element directly. Worst case scenario you would add a reference in React to the element, but you can't do that without modifying the child.

React doesn't make it easy to modify an element. You CAN see things like props and such in the incoming element. So I made an componentDidMount and went to work.

componentDidMount(){	
    const children = Array.isArray(this.props.children) ? this.props.children : [this.props.children];
    const newChildren = children.map( component => 
        React.cloneElement( component, {
        onChange: this.updateValue,
            value: this.state[ component.props.name ]
        })
	);
    this.setState({
        children: newChildren
    });
}

The part at the top is interesting. For some reason, React will give you an array in this.props.children if there was more than 1 child, and it will give you a single object representing the dom element/component if there is only 1 child. Why they didn't put it into an array (an array of 1 element or many) is beyond me. If you happen to know, post in the comments below!

However, that doesn't really work. Your inputs won't update correctly because the children themselves won't update. You could make a subcomponent object, but then we're just getting crazy. So we instead need to basically render it over and over as a clone.

So instead we move our cloneElement into a new method so it can be called every render.

renderChildren(){
    const children = Array.isArray(this.props.children) ? this.props.children : [this.props.children];
    const newChildren = children.map( component => 
        React.cloneElement( component, {
        onChange: this.updateValue,
            value: this.state[ component.props.name ]
        })
    );
    return newChildren;	
}
render(){
    return (
        <div>
        { this.renderChildren() }
            <button onClick={this.submitForm}>{this.props.callbackLabel}</button></div>
    )
}

Which really seemed excessive. I talked with some colleagues here at LearningFuze, and Scott, grand pubbah of React, scratched his head and says "yeah, that seems like the way". He did say something very sage, though: "That's pretty much what it does with elements. It rerenders them, or at least appears to". That's paraphrased, but it encompasses what seems to be true. React basically tears down the dom and rebuilds it over and over again. It does it in a way that obviously isn't that insane, as it works fairly well.

So that's about it. There may be better ways, but if there is one lesson to learn here: MAKE STUFF. You can't get into corners if you don't move. You can't figure out solutions if you don't make problems. So make new code every week to try things. You'll be amazed at the rabbit holes you fall down. Sometimes you will discover things that are noteworthy.

To view or add a comment, sign in

More articles by Daniel Paschal

  • curiouser and curiouser: a tale of css pseudo-elements

    A programming language is a set of rules. One of our jobs, as developers, is to understand those rules in order to make…

  • Google SEO: structured data

    SEO, or search-engine-optimization, for a long time was a game of figuring out what the search engines were looking for…

    2 Comments
  • CSS: font-display

    Custom Fonts on pages can be a cause of consternation when they don't load quickly. In the past, tricks usually…

  • css: font-face multi-source

    File this one under "that's cool, but probably not that useful" When specifying a font-face, you would normally specify…

  • More physical products meeting end of life due to support changes

    There have been a recent spate of product brickings that you should be familiar with. In this day and age, it is quite…

    1 Comment
  • Charter/Spectrum's security shutdown hints of interoperability problems to come

    It's not uncommon for companies, as they do mergers or shut down or simply determine a product isn't performing well…

  • Git 2.25.0 has landed

    Release notes here Some love for sparse-checkout (checking out a more skeleton version of a project) git log formatting…

  • My first experiences with AWS Lambda: a guide to trying node.js lambda

    Prologue I am first and foremost an monolithic person. I love starting up my own full servers.

  • History of Javascript

    Mocha, I mean Livescript, I mean Javascript, I mean ECMAscript has been around in some form since 1991. It has a very…

    2 Comments
  • nth-child/nth-last-child tricks

    CSS is rapidly on its way to being a very robust 'language'. There are many selectors that people are unaware of that…

    2 Comments

Others also viewed

Explore content categories