ReactJS: dynamic checkboxes from State
I'd probably set your state to contain an array of objects (representing your checkboxes), and a string that represents your filter. Each checkbox object would contain two properties, the text for the label, and the value of the checkbox.
For your initial state, you'd want this array to be empty, then during the componentDidMount
lifecycle, you'd perform your API call and set your state to include the information you received.
constructor(props) { super(props); this.state = { checkboxes: [], filter: 'ALL' }; //each checkbox would take the form of {label: 'some label', checked: true}}componentDidMount() { getData(response => { //some API call this.setState({ checkboxes: response.body }); });}
In order for your component to render these checkboxes, it needs to understand how your checkbox objects in your state relate to actual DOM elements. You might create a helper function that leverages .map
to do this. You can also leverage .filter
to apply your filter to each object in your state, and get rid of the ones that don't match your filter.
function renderCheckboxes() { const {checkboxes, filter} = this.state; return checkboxes .filter(checkbox => filter === 'ALL' || filter === 'CHECKED' && checkbox.checked || filter === 'UNCHECKED' && !checkbox.checked ) .map((checkbox, index) => <div> <label> <input type="checkbox" checked={checkbox.checked} onChange={toggleCheckbox.bind(this, index)} /> {checkbox.label} </label> </div> );}
Notice how each checkbox has an onChange attribute mapped to some function? You'll need to provide this to every checkbox that you render with the checked
attribute, since you'll be creating a Controlled Component, and your state will be controlling whether or not each individual component is checked. Your toggleCheckbox
function may look something like this:
function toggleCheckbox(index) { const {checkboxes} = this.state; checkboxes[index].checked = !checkboxes[index].checked; this.setState({ checkboxes });}
It also might be useful to create a function that sets your filter to a different string:
function updateFilter(filter) { this.setState({ filter });}
Finally, you can use these functions in your render
function to display your checkboxes as well as links to update your filter status (I also added some non-breaking spaces to separate each filter link):
render() { return ( <div> {renderCheckboxes.call(this)} <div> <h4>Filters ({this.state.filter})</h4> <a href="#" onClick={updateFilter.bind(this, 'ALL')}>ALL</a> | <a href="#" onClick={updateFilter.bind(this, 'CHECKED')}>CHECKED</a> | <a href="#" onClick={updateFilter.bind(this, 'UNCHECKED')}>UNCHECKED</a> </div> </div> );}
Here's an example of this working - minus the API call:
https://jsbin.com/bageyudaqe/edit?js,output
Hope this helps!