Nhan Nguyen
Nhan Nguyen

Reputation: 405

How can I dynamically render components when enter an input

I am trying to create a function dynamically render components when I enter input like this:

Mercury, Venus, Mars, Saturn

and it will return these components for me:

enter image description here

Here is my app structure:

src/App.js:

function App() {
  const [searchQuery, setSearchQuery] = useState("");
  const handleChange = (event) => {
    event.preventDefault();
    setSearchQuery(event.target.value);
  };

return (
        <div>
            <input
              id="inline-full-name"
              type="text"
              onChange={(e) => handleChange(e)}
            />
        </div>
        <div>
          <div className="md:w-2/3">
            <button
              type="button"
              value="Generate"
            >
              Generate
            </button>
          </div>
        </div>
  );
}

export default App

src/components/snippets/Earth.js src/components/snippets/Jupiter.js src/components/snippets/Mars.js src/components/snippets/Mercury.js src/components/snippets/Saturn.js src/components/snippets/Venus.js

How can I display these components when enter in input ?

Upvotes: 0

Views: 97

Answers (2)

Adam Jenkins
Adam Jenkins

Reputation: 55613

Easiest solution is to import them all.

  1. Create a file that contains your components exported by name
// components/snippets/planets.js

export { default as Jupiter } from './Jupiter';
export { default as Mars } from './Mars';
...
export { default as Earth } from './Earth';
  1. In App.js, import them all, then render only the ones you want
// src/App.js
import * as planets from 'components/snippets/planets';


const getComponentsFromSearchQuery = query => {
  // if there's no query, you probably want all the components
  if(!query) return Object.values(planets);

   // split by ',' and create an array of search items
   const filter = query.split(',').map(v => v.trim());


  return Object
      .entries(planets)
      // get all planets that match any of the items in the comma separated search string
      .filter([k]) => filter.some(f => k.indexOf(f) !== -1))
      // return just the component
      .map([k,v]) => v);
}


function App() {
  const [searchQuery, setSearchQuery] = useState("");
  const [components,setComponents] = useState(getComponentsFromSearchQuery(''));
  const handleChange = (event) => {
    event.preventDefault();
    setSearchQuery(event.target.value);
    setComponents(getComponentsFromSearchQuery(event.target.value))
  };

return (
        <div>
            <input
              id="inline-full-name"
              type="text"
              onChange={(e) => handleChange(e)}
            />
        </div>
        <div>
          <div className="md:w-2/3">
            <button
              type="button"
              value="Generate"
            >
              Generate
            </button>
          </div>
          { /* render the components */ }
          {components.map(C => <C/>)}
        </div>
  );
}

export default App


Upvotes: 1

Chuck
Chuck

Reputation: 804

First of all, you can not return multiple components in render function. It can be fixed like this.

return (
<>
// ...body here
</>
) 

You can return Mars like this.

...
// render -> return content
 {
   searchQuery === 'Mars' ? (
      <Mars />
   ) : null
 }
...

Upvotes: 1

Related Questions