Modularize and abstract react component functionality

后端 未结 2 2042
予麋鹿
予麋鹿 2021-01-16 19:55

I have below a working component that allows for a checkbox all and checkboxes. It works perfectly. However I hate the idea that I\'m stuck carrying all of this code around

相关标签:
2条回答
  • 2021-01-16 20:20

    The following example is in the right general direction I think, the general idea is to introduce a wrapper component for the related boxes, and then walk through the children in that component to tie them together.

    var CheckAll = React.createClass({
    render() {
      return <input type="checkbox" {...this.props} />
    }
    });
    var Checkbox = React.createClass({
    render() {
      return <input type="checkbox" {...this.props} />
    }
    });
    var CheckboxGroup = React.createClass({
    setAll(to) {
      var result = {};
      Object.keys(this.props.boxes).forEach(k => result[k] = to)
      this.props.onChange(result);
    },
    setOne(name, to) {
      var result = {};
      Object.keys(this.props.boxes).forEach(k => result[k] = this.props.boxes[k])
      result[name] = to;
      this.props.onChange(result);
    },
    enrichChild(child) {
      var boxes = this.props.boxes;
      var all = Object.keys(boxes).every(k => boxes[k]);
      if (child.type == CheckAll) {
        return React.cloneElement(child, { checked: all,
          onChange: () => this.setAll(!all)
        });
      } else if (child.type == Checkbox) {
        var name = child.props.name;
        return React.cloneElement(child, { checked: !!boxes[name],
          onChange: ({target}) => this.setOne(name, target.checked)
        });
      } else {
        return child;
      }
    },
    render() {
      return (
        <div>
          {React.Children.map(this.props.children, this.enrichChild)}
        </div>
      )
    }
    });
    
    
    var Test = React.createClass({
      getInitialState: function () {
        return {
          boxes: {
            a: true,
            b: false,
            c: false,
          }
        }
      },
      render: function () {
        return (
        <div>
          <CheckboxGroup
            boxes={this.state.boxes}
            onChange={boxes => this.setState({boxes})}
          >
            <CheckAll />
            <Checkbox name="a" />
            <Checkbox name="b" />
            <Checkbox name="c" />
          </CheckboxGroup>
        </div>
        )
      }
    })
    
    React.render(<Test/>, document.body)
    

    Here's a jsbin - https://jsbin.com/zomuxolevo/1/edit?js,output

    To allow for more flexibility with the children, you'd need to recursively walk them using something like this gist https://gist.github.com/dandelany/1ff06f4fa1f8d6f89c5e

    var RecursiveChildComponent = React.createClass({
      render() {
        return <div>
          {this.recursiveCloneChildren(this.props.children)}
        </div>
      },
      recursiveCloneChildren(children) {
        return React.Children.map(children, child => {
          if(!_.isObject(child)) return child;
          var childProps = {someNew: "propToAdd"};
          childProps.children = this.recursiveCloneChildren(child.props.children);
          return React.cloneElement(child, childProps);
        })
      }
    })
    
    0 讨论(0)
  • 2021-01-16 20:28

    I hacked this together using some jQuery, and lodash.

    Here's the example running.

    Note, this example goes into the DOM to get the data needed. None of the state of these checkboxes are stored by the component. As far as I can tell there is no true "React" way to do this. (I am very open to suggestion.)

    var Checkbox = React.createClass({
      componentDidMount: function () {
        var component = React.findDOMNode(this)
        var $component = $(component)
        if ($component.attr('id')) {
          var selector = 'input'
          selector += '[data-component=Checkbox]'
          selector += '[for=' + $component.attr('id') + ']'
          var $forComponents = $(selector)
          $component.on('change', function () {
            var value = $component.prop('checked')
            $forComponents.each(function () {
              $forComponent = $(this)
              $forComponent.prop('checked', value)
            })
          })
          $forComponents.on('change', function () {
            var values = $forComponents.map(function () {
              var $forComponent = $(this)
              var value = $forComponent.prop('checked')
              return value
            })
            var simple = _.chain(values).unique().value()
            if (simple.length === 1 && simple[0] === true) {
              $component.prop('checked', true)
            } else {
              $component.prop('checked', false)
            }
          })
        }
      },
      render: function () {
        return (
        <input
           type='checkbox'
           data-component='Checkbox'
           {...this.props}/>
        )
      }
    })
    
    var Test = React.createClass({
      render: function () {
        return (
        <div>
          Select All: <Checkbox id='alpha'/><br/>
          <Checkbox htmlFor='alpha'/><br/>
          <Checkbox htmlFor='alpha'/><br/>
          <Checkbox htmlFor='alpha' defaultChecked/><br/>
          <Checkbox htmlFor='alpha'/><br/>
          <Checkbox htmlFor='alpha'/><br/>
        </div>
        )
      }
    })
    
    React.render(<Test/>, document.body)
    
    0 讨论(0)
提交回复
热议问题