3

I'm pretty new to React and React hooks in general,

I'm building a react app for my final project and I wanted to make some component (Advanced search in this example) as generalized as possible which means I want to pass "dataFields" and the component should be updated with a unique state value that originated from those data fields.

I know that I can use a general state and store changes in it with an array but I read that it's bad practice.

this is what I have now:

const [title,updateTitle] = useState({"enable":false,"value": "" });
const [tags,updateTags] = useState({"enable":false,"value": "" });
const [owner,updateOwner] = useState({"enable":false,"value": "" });
const [desc,updateDesc] = useState({"enable":false,"value": "" });

And I try to use this to achieve the same thing:

if(props?.dataFields) {
    Object.entries(props.dataFields).forEach ( ([key,value]) => {
        // declare state fields
        const [key,value] = useState(value)
    });
}

what is the proper way of doing it? is there is one?

yoni hodeffi
  • 33
  • 1
  • 3
  • You can't call a hook inside a conditional, so your `const [key,value] = useState(value)` will not work. – JMadelaine Mar 14 '20 at 10:06
  • That is a violation in terms of hooks specifications. They should be inside of function not in any block. – Jai Mar 14 '20 at 10:11
  • Do you need the component to be totally generic? Advanced searches usually either have an individual field for each property that they search across, or they take an array of strings and use those strings to search across all available properties. What you're trying to do is store individual pieces of state for an unknown data structure - a very difficult task indeed. Does your project actually NEED this generic search component? – JMadelaine Mar 14 '20 at 10:16
  • @JMadelaine My project has different models, Posts \ Users \ Publishers \ Addresses etc So I'd rather have the advanced search comp as generic as possible, Since all the models are being connected to mongoDB and i'm doing regex search on them, the query is similar on all of those models. I just need to be able to create state fields from a props array. Any suggestions? – yoni hodeffi Mar 14 '20 at 11:16
  • You may just have to create individual components for each model. Or take an array of strings that search across all properties. – JMadelaine Mar 14 '20 at 11:17

1 Answers1

3

Do 4 lines of useState or useReducer (local)

I would suggest someting like this for the initial state

  const setItem = (enable = false, value = '') => ({ enable, value });

  const [title, updateTitle] = useState(setItem());
  const [tags, updateTags] = useState(setItem());
  const [owner, updateOwner] = useState(setItem());
  const [desc, updateDesc] = useState(setItem());

And you also can useReducer and define the initial state.

I add an example for useReducer and case dor change title.value

import React from 'react';
import { useReducer } from 'react';

const setItem = (enable = false, value = '') => ({ enable, value });

const initialState = { title: setItem(), tags: setItem(), owner: setItem(), desc: setItem() };

function reducer(state, action) {
  switch (action.type) {
    case 'CHANGE_TITLE':
      return { ...state, title: setItem(null, action.payload) };
    default:
      return state;
  }
}

function MyFirstUseReducer() {
  const [state, dispatch] = useReducer(reducer, initialState);

  const updateTitle = ev => {
    if (ev.which !== 13 || ev.target.value === '') return;
    dispatch({ type: 'CHANGE_TITLE', payload: ev.target.value });
    ev.target.value = '';
  };

  return (
    <>
      <h2>Using Reducer</h2>
      <input type="text" onKeyUp={updateTitle} placeholder="Change Title" />
      <div>
        <span>The State Title is: <strong>{state.title.value}</strong></span>
      </div>
    </>
  );
}

export default MyFirstUseReducer;
Omer
  • 3,232
  • 1
  • 19
  • 19