The basic idea is to have your components take optional params that are themselves components. ESPseudoish code:
// In your components...
let DefaultListItem = (content) => <li className="foo">{content}</li>
let DefaultList = (items, Li=DefaultListItem) => <ul>{items.map(Li)}</ul>
let SortableItem = (content) => <li className="handle" on-drag={(e) => dispatch('dragStart', hash(content))>{content}</li>
let SortableList = (items, Li=SortableItem) => <DefaultList {...this.props} />
let EditableList = (items, List=DefaultList, Li=SortableItem) => {
<div><List {...this.props} /><button>Edit</button></div>
}
let SearchResultHighlighter = (text) => <span className="imagine-this-highlighted">{text}</span>
// -- In use...
let source = ['foo', 'bar', 'baz']
render(<SortableList items={ source.map(SearchResultHighlighter) } />)
let ImageItem = (url) => <li><img src={url} /></li>
render(<EditableList items={ source.map(x => x + '.jpg') } Li={ImageItem} />)
There's a lot of design space to play around with. For a widely reusable library, I want something like Clojure's protocols or Rust's traits so I can indicate to people what the component needs/provides without them looking at the source.
Thanks. I've been thinking about the component provides/needs issue as well. I was thinking of wrapping any passed in sub-component in "polyfill / rewire" component created from a factory that can be passed the propTypes that the parent component expects it's child to support and a map from props it will be passed to the props it actually supports. Ideally I'd like to be able to do something like switch between react-material and react-bootstrap on the fly.