0

I am at the very beginning of creating an icon picker for sanity.io with react icons npm package. I am stuck on trying to map over an object and returning the right code for react to work using Object.values(ReactIcons).map... if I just console log one of the objects values like so ReactIcons.Fa500Px I get the following function

ƒ (props) {
  return Object(__WEBPACK_IMPORTED_MODULE_0__lib__["a" /* GenIcon */])({"tag":"svg","attr":{"viewBox":"0 0 448 512"},"child":[{"tag":"path","attr":{"d":"M103.3 344.3c-6.5-14.2-6.9-18.3 7.4-…

Now If I take the same code form the console.log and put it in a jsx or React component brackets like so <ReactIcons.Fa500Px /> it renders the icon just fine

However if I try to do that inside the map method with something like this I just get a bunch of elements in the dom the look like <x></x>. However the console.log(x) returns a series of the functions that are the same format as the one above that I just placed inside brackets before, which resulted in a icon being rendered.

{Object.values(ReactIcons).map(x =>{
    return (
      <>
    {console.log(x)}
    <x/>
    </>
    );
  })}

My final attempt to get this to work was to create a Icon function and pass props into it and render it as a component. Which did not work but here is that attempt.

function Icon(props){
  return(
    <>
      {props.value}
    </>
  )
}

{Object.values(ReactIcons).map(x =>{
 return (
    <>
      {console.log(x)} 
      <Icon value={x}/> 
    </>
   );
 })}

Here's the entire code base in order just to make sure maybe I am putting my Icon function in the wrong place.

import React from 'react'
import PropTypes from 'prop-types'
import FormField from 'part:@sanity/components/formfields/default'
import PatchEvent, {set, unset} from 'part:@sanity/form-builder/patch-event'
import * as ReactIcons from 'react-icons/fa'

console.log(ReactIcons);

const createPatchFrom = value => PatchEvent.from(value === '' ? unset() : set(String(value)))

function Icon(props){
  return(
    <>
      {props.value}
    </>
  )
}


class IconPickerCustom extends React.Component{

    static propTypes = {
        value: PropTypes.string,
        onChange: PropTypes.func.isRequired
    };

    render = () =>{
        const {type, value, onChange} = this.props
        return (
          <>
            <FormField label={type.title} description={type.description}>
              <input
                type="text"
                value={value === undefined ? '' : value}
                onChange={event => onChange(createPatchFrom(event.target.value))}
                ref={element => this._inputElement = element}
              />
            </FormField>
            {Object.values(ReactIcons).map(x =>{
              return (
                <>
              {console.log(x)} // has same result as console log below, except it is all the icons
              <Icon value={x}/> //neithr works
              <x /> //neither works
              </>
              );
            })}
            {console.log(ReactIcons.Fa500Px)}
            <ReactIcons.Fa500Px/>
          </>
        )
    }
}

export default IconPickerCustom;
4
  • Do you have a minimal runnable example that I can clone? I've tried in a Codesandbox here but I can't add the Sanity plugin code as import "part:..." is not working outside of Sanity Studio. Commented Mar 1, 2020 at 22:19
  • You want the icons in a select dropdown? Or just aligned in the DOM as buttons? Commented Mar 1, 2020 at 22:20
  • Here's a repo with a working sanity studio with the code in it in the file github.com/wispyco/sanity-studio-icon in the file here github.com/wispyco/sanity-studio-icon/blob/master/schemas/… Commented Mar 1, 2020 at 22:24
  • @AWolf for now just aligned as buttons, I'm still figuring out how the UI is gonna work because there are a lot of icons, I'll probably have to implement a search but for now I just want to even output the icons at all. Commented Mar 1, 2020 at 22:25

2 Answers 2

1

I guess that you would like to loop in the object key instead

            {Object.keys(ReactIcons).map(x =>{
               let Elm = ReactIcons[x]
              return (
                <Elm /> 
              );
            })}

I'm just guessing I'm not sure

Sign up to request clarification or add additional context in comments.

4 Comments

I tried the keys, but I need the values. Thanks tho.
the keys just give me the name like FaIcon so on, where as the value gives me everything that needs to go in the component
Object.keys like Fadi wrote will work or with Object.values you can write it like { Object.values(ReactIcons).map((Icon, index) =>{ return <Icon key={index}/>; }) }
@AWolf, it works with .values now it had to be a capital X to recongize it as a react component.
0

I got help form the sanity slack, and this ended up solving my problem

import React, { useState } from 'react';
import PropTypes from 'prop-types'
import FormField from 'part:@sanity/components/formfields/default'
import PatchEvent, {set, unset} from 'part:@sanity/form-builder/patch-event'
import * as ReactIcons from 'react-icons/fa'

// const createPatchFrom = value => PatchEvent.from(value === '' ? unset() : set(String(value)))

const Icon =({name}) =>{
  const TagName = ReactIcons[name];
  return !!TagName ? <TagName /> : <p>{name}</p>;
}

const Box = ({icon}) =>{
  return(
    <>
        {icon.map((iconsz) => {
            return(
              <>
              <button>
                <Icon name={iconsz}/>
              </button>

              </>
            )
          }     
        )}
    </>
  ) 
}

class IconPickerCustom extends React.Component{

    constructor(props){
      super(props)
      const arr = [];

      Object.keys(ReactIcons).map(go => { 
        arr.push(go);
          this.state = {icon: arr};
        }
      )
      this.handleChange = this.handleChange.bind(this)

    }

    // createPatchFrom = value => PatchEvent.from(value === '' ? unset() : set(String(value)));

    handleChange = event => {
      const value = event;
      const arr = [];
      Object.keys(ReactIcons).map(go => 
        { 
          if(go.toLowerCase().includes(value)){
            arr.push(go);
          } 
          this.setState({
            icon: arr
          });
        }
      )
    };

    render = () =>{
      const {icon} = this.state

        return (
          <>
            <input
              type="text"
              onChange={event => this.handleChange(event.target.value)}
            />
            <Box icon={icon}/>
          </>
        )
    }
}

export default IconPickerCustom;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.