Search code examples
javascriptreactjssearchsanityuse-state

React update state of component after search through object


I have an object that is outputted from the reactIcons npm package https://www.npmjs.com/package/react-icons I am importing everything from one of the folders with import * as ReactIcons from 'react-icons/fa' I am using sanity studio, I created a text input that takes the value searched and runs a search function that runs a includes on the values from the object I grabbed from the reactIcons fa folder and log's the vales that match. Now I want to take those values and update a react component with useState() Howerver I get the following error Uncaught ReferenceError: setIcon is not defined and SetIcon is the setter function from useState array. Here is my code so far

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'


console.log(ReactIcons);

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

const Example = value => {
  const [icon, setIcon] = useState();

  return (
   <div>{icon}</div>
  );
}

const search = value => {
  console.log(value);
    Object.keys(ReactIcons).map(go => {
    if (go.toLowerCase().includes(value) === true){
      console.log(go);
      setIcon(go);
    }
  })
}



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>
            <input
              type="text"
              onChange={event => search(event.target.value)}
            />
            {Object.values(ReactIcons).map(X =>{
              return (
                <>
              <X/>
              </>
              );
            })}
            {console.log(ReactIcons.Fa500Px)}
            <ReactIcons.Fa500Px/>
            <Example/>
          </>
        )
    }
}

export default IconPickerCustom;

Solution

  • React has two types of components, class components and function components (formerly stateless components). Hooks are used in function components when you realize you need state inside a function component and prefer not to convert it to a class component.

    The useState() Hook allows us to add state in a function component.

    Class Component

    //initialize state
    constructor(props) {
        super(props);
        this.state = {foo: bar};
    }
    
    //set state
    this.setState({foo: baz});
    
    //read state
    this.state.foo;
    

    Function Component
    (with useState() Hook)

    //initialize state
    const [icon, setIcon] = useState("myInitialValue");
    
    //set state
    setIcon("myNewValue");
    
    //read state
    {icon}
    

    That being said, you already have a class component so no need to use hooks here.

    class IconPickerCustom extends React.Component{
    
    constructor(props) {
        super(props);
        this.state = { icon: "nothing" };
    }
    
    static propTypes = {
        value: PropTypes.string,
        onChange: PropTypes.func.isRequired
    };
    
    const createPatchFrom = value => PatchEvent.from(value === '' ? unset() : set(String(value)));
    
    const search = value => {
        Object.keys(ReactIcons).map(go => 
            ({ go.toLowerCase().includes(value) ? 
               this.setState({icon:go}) : null;}) 
    }
    
    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>
            <input
              type="text"
              onChange={event => search(event.target.value)}
            />
            {Object.values(ReactIcons).map(X =>{
              return (
                <>
              <X/>
              </>
              );
            })}
            {console.log(ReactIcons.Fa500Px)}
            <ReactIcons.Fa500Px/>
            <Example/>
          </>
        )
    }
    }
    
    export default IconPickerCustom;
    

    You are going to want something along those lines. Let me know if you have any questions.