#StackBounty: #reactjs #react-hooks #use-reducer react: getting api results into a table using useReducer and functional component

Bounty: 500

I’m brand spanking new to react. I am officially done beating my head against a wall. I just can’t figure this out. This is my situation:

I am trying to get the results of an API call into a table. I have the call to the API working and results coming back. I am stuck on how to get my array updated with the data that came back. After that is done then I can populate the table with the data (at least logically that’s the way what my brain tells me).

Initial form state setup:

const initialFormState = {
    fileTypeId : '',
    companyMasterId: '',
    investmentCompanyId: '',
    startDate: '',
    endDate: '',
    result: '',
    fileLogs: []
}

All of the fields above are fields on the formdatabase. The API call takes these parameters to call a stored procedure that returns a result set based on the search parameters. fileLogs[] is where I want to put the data that comes back. I wasn’t sure if I need to move it out of this setup and use useState just for that as a separate thing?

reducer initialization:

 const [formState, dispatch] = useReducer (formReducer, initialFormState)

reducer setup

formReducer.js

import actionTypes from "./actionTypes"

const formReducer = (state, action) => {
    switch (action.type) {
        case actionTypes.handle_input_text:
            return {
                //using the spread operator (…state) to copy across all the properties and values from the state object. 
                //then we can modify the values of specific state properties by explicitly declaring them again with a new value.
                ...state,
                [action.field]: action.payload,
            }
        case actionTypes.toggle_consent:
            return{
                ...state,
                hasConsented: !state.hasConsented
            }
        case actionTypes.on_success:
            return{...state, filelogs: action.payload}     
        default:
            return state
    }
}
export default formReducer

API call

function getFileRouteLogs (e)  {
        e.preventDefault()

        apiService.getFileRouteLogs(
            formState.fileTypeId,
            formState.companyMasterId,
            formState.investmentCompanyId,
            formState.startDate,
            formState.endDate,
            formState.result
        )
         .then((response)=>{
            //  dispatch({
            //     type: actionTypes.on_success,
            //     // payload: [...formState.fileLogs,  response.data]
            //     payload: response.data
            //     })
            formState.fileLogs = response.data
            console.log(response.data)
        }) 

Handler for form input changes

const handleInputChange = (e) => {
        dispatch({
            type: actionTypes.handle_input_text,
            field: e.target.name,
            payload: e.target.value
        })
    }

Form for input

return (
            <div>
                <h1>File Route Log Search</h1>
                <hr />
                <h2>Form field area</h2>
                <Form onSubmit={getFileRouteLogs}>
                    <FormGroup row>
                        <Label for="fileTypeId" sm={2}>FileTypeId</Label>
                        <Col sm={2}>
                            <Input  type="text" name="fileTypeId" value={formState.fileTypeId} onChange={(e) => handleInputChange(e)}></Input>
                        </Col>
                    </FormGroup>
                    <FormGroup row>
                        <Label for="companyMasterId" sm={2}>CompanyMasterId</Label>
                        <Col sm={2}>
                            <Input id="companyMasterId" type="text" name="companyMasterId" value={formState.companyMasterId} onChange={(e) => handleInputChange(e)} ></Input>
                        </Col>
                    </FormGroup> 
...

Attempted table setup to hold data

const FileRouteLogTable = ({formState}) => {
  return (
    <table className="table">
      <thead>
        <tr>
          <th>FileRouteLogId</th>
          <th>CompanyMasterId</th>
          <th>FileTypeId</th>
          <th>Result</th>
          <th>InvestmentCompanyMasterId</th>
          <th>FileName</th>
        </tr>
      </thead>
      <tbody>
      { (formState.length > 0) ? formState.map( (form, index) => {
           return (
            <tr key={ index }>
              <td>{ form.fileRouteLogId }</td>
              <td>{ form.companyMasterId }</td>
              <td>{ form.fileTypeId}</td>
              <td>{ form.result }</td>
              <td>{ form.investmentCompanyMasterId }</td>
              <td>{ form.fileName }</td>
            </tr>
          )
         }) : <tr><td colSpan="5">Enter search parameters...</td></tr> }
      </tbody>
    </table>
  );
}

export default FileRouteLogTable

I was going to try to use a react-table, but I got stuck on updating the data before I could do any table stuff

import { useTable } from 'react-table'
function FileRouteLogTable({ columns, formState }) {
    // Use the state and functions returned from useTable to build your UI
    const {
      getTableProps,
      getTableBodyProps,
      headerGroups,
      rows,
      prepareRow,
    } = useTable({
      columns,
      formState,
    })
  
    return (
      <table {...getTableProps()}>
        <thead>
          {headerGroups.map(headerGroup => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map(column => (
                <th {...column.getHeaderProps()}>{column.render('Header')}</th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {rows.map((row, i) => {
            prepareRow(row)
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map(cell => {
                  return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
                })}
              </tr>
            )
          })}
        </tbody>
      </table>
    )
  }
  export default FileRouteLogTable

Any help would be greatly appreciated. All the examples I look at don’t have my combination of factors:

  • functional component
  • use useReducer
  • use axios
  • everything not on one page
  • does not do an API GET call on page load using useEffect
  • does not just display the results in the console log


Get this bounty!!!

#StackBounty: #reactjs #json #react-hooks #use-state updating object inside array inside object using prevState and the useState hook

Bounty: 50

I’d like to remove a nested object based on the id is equal to a passed prop. At the moment, the entire object is replaced. I’m missing something, when trying to update the state using useState probably with the way I’m looping my object?

UPDATE: The question was closed in response to available answers for updating nested objects. This question involves arrays which I believe are part of the issue at hand. Please note the difference in nature in this question with the forEach. Perhaps a return statement is required, or a different approach to the filtering on id..

my initial object looks like this:

{
  "some_id1": [
    {
      "id": 93979,
      // MORE STUFF
   
    },
    {
      "id": 93978,
      // MORE STUFF
    }
  ],
  "some_id2": [
    {
      "id": 93961,
      // MORE STUFF
    },
    {
      "id": 93960,
      // MORE STUFF
    }
  ]
}

and I go through each item as such:

for (const key in items) {
        if (Object.hasOwnProperty.call(items, key)) {
            const element = items[key];
            element.forEach(x => {
                if (x.id === singleItem.id) {
                    setItems(prevState => ({
                        ...prevState,
                        [key]: {
                            ...prevState[key],
                            [x.id]: undefined
                        }
                    }))
                }
            })
        }


Get this bounty!!!

#StackBounty: #javascript #reactjs #react-hooks Using Location State in Functional Component

Bounty: 50

I’m working on a React project that requires the app URL to be fully-declared, static and immutable, so just:

https://exampleurl.com/path/to/app/index.html

..but none of the following:

https://exampleurl.com/path/to/app/

https://exampleurl.com/path/to/app/index.html?query=value

https://exampleurl.com/path/to/app/subdir/index.html

So, the project uses state and withRouter to provide basic app navigation. The responsible component is as follows:

import React from 'react';
import { withRouter} from "react-router-dom";
import RenderNav from './RenderNav';
import Cohort from '../view/Cohort';
import Holdings from '../view/Holdings';
import Policy from '../view/Policy';
import Search from '../view/Search';
import Start from '../view/Start';
import Training from '../view/Training';
import WatchList from '../view/WatchList';

class RenderDisplay extends React.Component {
  constructor(props) {
    super(props);
    this.state = this.props.location.state || { activeDisplay: 'start' };
    this.props.history.replace(this.props.location.pathname, this.state);
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.props.location !== prevProps.location) {
      this.setState(this.props.location.state);
    }
  }

  setDisplay() {
    let displayMode = [];
    let d = this.state.activeDisplay;

    switch(d) {
      case 'start': displayMode = [
        <Start key={`display-${d}`} />
      ]; break;

      // ...and so on - activeDisplay determines displayMode (and so screen contents)

      default: displayMode = [<div>Error</div>]; break;
    }; return displayMode;
  }

  render() {
    return (
      <div className="container">
        {this.setDisplay()}
      </div>
    );
  }
}

export default withRouter(RenderDisplay);

The location.state object is set by the <Link /> component:

<Link to={{ state: {activeDisplay: 'start'} }}>
  <button type="button">Home</button>
</Link>

The result is normal browser navigation throughout the app while the URL remains unchanged.

My question is: how can the class-based RenderDisplay component above be converted to a functional component (using hooks)?

I’ve tried several permutations of useEffect, useState, and useLocation, but I clearly don’t understand hooks well enough to reproduce the behavior of the class-based component above.


Get this bounty!!!

#StackBounty: #reactjs #react-hooks #use-context #createcontext How to pass a value using `createContext` from parent to child's ch…

Bounty: 50

Instead of passing props from parent to child1(parent of child2) ->to child2,
I want to use createContext and receive the value with useContext.

What I tried to do is not correct because and I’m getting an error **'booleanContext' is not defined**.

How can I pass the createContext state/value ?

App.js

CreatePass is a component inside SignUp

  const [signUpFirst, setIfSignUp] = useState(true);
  const booleanContext = createContext(setIfSignUp);
  
 return (
    <booleanContext.Provider value={setIfSignUp}>

   <div>
     </Switch>
   <Route exact path='/signup'>
          <SignUp homePage={exitSignUpPage} setUserNumber={setUserID} />
        </Route>
        <Route exact path='/home'>
          <Home userIDNumber={userID} setIfSignUp={setIfSignUp} />
        </Route>
      <CreatPass /> 
      </Switch>
     </div>
    </booleanContext.Provider>
  );

SignUp.js

  render() {
    return (
      <div className='signUp-div'>
        <Header />
        <Router history={history}>
          <div className='form-div'>
            <Redirect to='/signup/mobile' />
            <Switch>
              <Route exact path='/signup/mobile' component={MobileNum} />
              <Route exact path='/signup/idnumber'>
                <IdentNumber setPersonalID={this.props.setUserNumber} />
              </Route>
              <Route exact path='/signup/password'>
                <CreatePass />
              </Route>
            </Switch>
          </div>
        </Router>
      </div>
    );
  }

CreatePass.js //'booleanContext' is not defined no-undef

const CreatePass = () => {
  const changeBooleanValue = useContext(booleanContext);

  const handleClickButton = () => {
      changeBooleanValue(true);
  };

  return (
    <div className='form-div'>
  <button onClick={handleClickButton}>Click</button>
    </div>
  );
};
export default CreatePass;

Edit – Update:

This solution is not good it’s the same value as I did above booleanContext is undefined –

export const booleanContext = createContext(); // default value is undefiend
...
const App = () => 
     return(
     <booleanContext.Provider value={setIfSignUp}>
      <CreatPass />        
     </booleanContext.Provider>
      )
}
export default App;

Will be glad for explanations


Get this bounty!!!

#StackBounty: #reactjs #react-hooks How to run code on React.useReducer bailout

Bounty: 200

I am trying to write a library that processes dispatched useReducer actions. However, they need to be processed only once I have the new react state.

The idea in the following example is to buffer all the actions as they happen and then after the component rerenders get the new state and send all the buffered actions with the new state into the processor (simple logger function in this case). Problem is, that won’t work if the component bails out of rendering, because the component won’t rerender and so the useEffect callback won’t get called either.

function logger(action, state) {
    // this should log every action immediately once its processed by react
    // state must be up-to-date (after all batched state changes are processed)
    console.log({action, state});
}
const buffer = [];

const Component = () => {
    const [state, dispatch] = useReducer(
        (state, action) => {
            // bail out if there is no change
            if (action.value === state.someState) return state;
            return {someState: action.value};
        },
        {someState: 1}
    );
    const loggedDispatch = (action) => {
        dispatch(action);
        // Can't run the logger here as I don't have the new state yet
        // so I am buffering the actions instead for later
        buffer.push(action);
    };
    useEffect(() => {
        // Now I have the new state, so I can run the logger
        // Problem is that this won't run if the reducer bailed out of render
        while (buffer.length) {
            logger(buffer.shift(), state);
        }
    });
    return (
        <div>
            <div onClick={() => loggedDispatch({value: 1})}>Set to 1</div>
            <div onClick={() => loggedDispatch({value: 2})}>Set to 2</div>
        </div>
    );
};

Any idea how to fix this with react hooks?

With class components it was possible to use

this.setState(state => state, function () {
    console.log('This runs regardless of bailout');
})

But react hooks such as useState or useReducer don’t support the second parameter.

Codesandbox: https://codesandbox.io/s/friendly-pine-lebrb?file=/src/App.js


Get this bounty!!!

#StackBounty: #javascript #reactjs #react-hooks #react-grid-layout How to handle condition rendering in react

Bounty: 100

I am using react-grid-layout This to enable drag and drop and resizing in my website.
SO drag and drop I am able to achieve and storing my layout to local storage is also done.

I am using Local storage to save my layout for better user experience using This example

the thing is what I am trying to do is conditionally give height and width to boxes, like if empName==="steve" than width should be 5 or else it should be 3

So what I did is

const generateLayout = () => {
  const p = data1 || []; //props;
  return p[0].comp_data.map(function (item, i) {
    console.log(item);
    if (item.empName === "steve") {
      return {
        x: (i * 2) % 12,
        y: Math.floor(i / 6),
        w: 2,
        h: 4,
        i: i.toString()
      };
    } else {
      return {
        x: (i * 2) % 12,
        y: Math.floor(i / 6),
        w: 4,
        h: 2,
        i: i.toString()
      };
    }
  });
};

The above approach does not work as required.

Here is the full working code

Edit update

I changed my data, as it was wrong I was looping through p[0]

Now what I did is I created one data for tabs That will show menu ie

    let tabData = [
    {
        tab: 'info',
        id: 1,
    },
    {
        tab: 'info1',
        id: 2,
    },
];

and the other one I have is compData that will have emp status

LIke below

    let data1 = [
    {
        comp_data: [
            {
                empId: 1,
                empName: 'el1',
            },
            {
                empId: 2,
                empName: 'el2',
            },
        ],
    },
    {
        comp_data: [
            {
                empId: 11,
                empName: 'el11',
            },
            {
                empId: 12,
                empName: 'el22',
            },
        ],
    },
];

Important — actually in my real scenario I am getting all the tabs at one go than I click on one tab get id of that and get compData for that id from backend but here I cannot do it so I put in data1 two objects one for first company and other for other company.

I think this the way for write explanation here

updated code sandbox please check


Get this bounty!!!

#StackBounty: #reactjs #react-hooks #react-select useState does not update from the state immediately

Bounty: 50

useState does not update the state immediately.

I’m using react-select and I need to load the component with the (multi) options selected according to the result of the request.

For this reason, I created the state userQueues, to store the value of the queues constant.

It turns out that when loading the component, the values ​​are displayed only the second time.

I made a console.log in the queues constant and in the userQueues state.

The first time the component is loaded, the value of queues results in an array with values, while userQueues results in an empty array.

First time to load the component
enter image description here

Second time I load the component
enter image description here

I’m not sure if this is exactly the problem, but I can’t immediately display the values ​​in the component.

enter image description here

const initiaValues = {
   name: '',
   email: '',
   password: ''
}
const [user, setUser] = useState(initialValues);
const [userQueues, setUserQueues] = useState([]);
useEffect(() => {
  (async () => {
    if (!userId) return;

    try {
      const { data } = await api.get(`/users/${userId}`);
      setUser((prevState) => {
        return { ...prevState, ...data };
      });

      const queues = data.queues.map((q) => ({
        value: q.id,
        label: q.name,
      }));
      setUserQueues(queues);

      console.log(queues);
      console.log(userQueues);
    } catch (err) {
      mdtoast(err);
    }
  })();

  return () => {
    setUser(initialValues);
  };
}, [userId, open]);

return (
  <Select
    defaultValue={userQueues}
    options={queues}
    onChange={handleChange}
    isMulti
  />
);


Get this bounty!!!

#StackBounty: #javascript #reactjs #react-hooks #react-select #effector React Effector State Management Based on Dropdown

Bounty: 50

I’m using React Hooks and Effector to try and render data onto a card. The data will be driven off a React-Select dropdown (which represents different countries), and the idea is that the user will be able to add selections based on those countries, kinda like a TODO app.

However, I’m finding that whenever I go back to a previous dropdown selection, the data doesn’t save. I’m using effector, hooks, react-select and react-jss for styling. The team gets passed as a prop from a React-Select component.

const PlayerComponent = ({ containerStyles, team }) => {

    const [items, setItems] = useState([]);

    const teamsStore = useStore(testTeams);
    const playersStore = useStore(testPlayers);

    useEffect(() => {

        const playersByTeam = playersStore.filter(
            (player) =>
                player.teamId ===
                teamsStore.find(function (t) {
                    return t.label === team;
                }).teamId
        );
    
        setItems(
            playersByTeam.map(function (player) {
                let players = { name: player.name };
                return players;
            })
        );
    }, [playersStore,team,teamsStore]);

    function onAddButtonClick() {
        setItems((prev) => {
            const newItems = [...prev];

            newItems.push({
                name: `Player ${newItems.length + 1}`
            });

            playersStore.push({
                name: `Player ${newItems.length + 1}`
            });

            return newItems;
        });
    }

    function renderAddButton() {
        return (
            <Row
                horizontal='center'
                vertical='center'
                onClick={onAddButtonClick}
            >
                Add Player
            </Row>
        );
    }

    return (
        <CardComponent
            containerStyles={containerStyles}
            title={team}
            items={[
                <Row horizontal='space-between' vertical='center'>
                    <span>
                        Create new player
                    </span>
                    {renderAddButton()}
                </Row>,
                ...items.map((item, index) => (
                    <Player index={index} item={item} />
                ))
            ]}
        />
    );
};

And this is my Player component, which represents a row each:

function Player({item = {} }) {
    return (
        <Row horizontal='space-between' vertical='center'>
            <Row>
                <span>{item.name}</span>
            </Row>
        </Row>
    );
}

Here’s an example image. Basically, after selecting a country (say England) from a dropdown, I can add a player and it will render on the card- however, when I select a different country and go back the previous country, the added players disappear. Any ideas how to solve this? I’m cracking my head on the onAddButtonClick() function right now…

enter image description here


Get this bounty!!!

#StackBounty: #arrays #reactjs #react-hooks #state #prop How to use a useState function in another component with props?

Bounty: 50

I write a React.js note web application where a user can add up to 10 notes.

I use map() to iterate the array of notes, and a useState(1) hook to update its count (the default number of notes is 1), so I would like to do something like this:

  {[...Array(noteCount)].map((_, i) => <Note onUpdateNoteCount={() =>setNoteCount(n => n - 1)} key={i} />)}

The thing is that the Note() component is inside a Main() component which is in the App() component, so I want to get the needed values as props of App(), and than use them in Note(), but can not figure out how and where to put it.

Thanks!

App.js

  import React from 'react';
  import Header from './Header';
  import Main from './Main';
function App () {
  const [noteCount, setNoteCount] = React.useState(1);
  function multiplyNoteComponent () {
    if (noteCount < 20) {
      setNoteCount(n => n + 1)
    }
    else {
      alert('too many notes. remove or combine some of them together!')
    }
  }
  return (
    <div>
      <Header/>
      {[...Array(noteCount)].map((_, i) => <Main onUpdateNoteCount={() =>setNoteCount(n => n - 1)} key={i} />)}

      <button
            style={{left: '5%'}}
          id='addNoteBtn'
          onClick={multiplyNoteComponent}
          title='Add a note'
         >
        +
      </button>
    </div>
  );
}
  export default App;

Main.js

    import React from 'react';
    import Note from './Note';
function Main () {
    return (
        <main>
            your notes are:
            <Note/>
        </main>
    )
}
    export default Main;

Note.js

    import React from 'react';
function Note () {
    return (
        <div> <button title='delete note' onClick={}>X</delete>
            <li>
                <input type='text'/>
            </li>
        </div>
    )
}
    export default Note

Edit: the reason I think I need the setNoteCount() function to be used in the Note() component, is for the count down when a note is being deleted (every note has its own delete button).


Get this bounty!!!