简体   繁体   English

如何在 React 中映射 2 个数组并渲染到表

[英]How to map over 2 Array in React and render to Table

I am creating a stock app that allows the user to search stock prices by calling a Stock API and search any stock and get back its price.我正在创建一个股票应用程序,它允许用户通过调用股票 API 来搜索股票价格并搜索任何股票并取回其价格。

Im storing the prices on a table, however the I want to be able to store the users input into the table as well.我将价格存储在表上,但是我希望也能够将用户输入存储到表中。

My strategy has been to store the user's search input into an array "symbolArray" and the api information into a 'dataArray."我的策略是将用户的搜索输入存储到一个数组“symbolArray”中,并将 api 信息存储到一个“dataArray”中。

So heres my issues.所以继承人我的问题。 I am able to map over the "dataArray" and render it to the table.我能够映射“dataArray”并将其呈现到表格中。 BUT i need to map over "symbolArray" and render it into the table thats already rendering items from the "data Array."但是我需要映射“symbolArray”并将其渲染到已经从“数据数组”渲染项目的表中。

Heres what I have so far这是我到目前为止所拥有的

const Quotes = ()=> {

//I call their states
const [symbolArray, setSymbolArray] = useState([])
const [dataArray, setDataArray] = useState([])


//this function stores, and calls the api data that the user searches for


function getData() {

  fetch(url)
        .then(res => res.json())
        .then(data =>{
          
            dataArray.push(data)
            
        })
        
}

// this is also activated when the user searchs. their input is pushed to the array of stock ticker symbols

const addingStuff = ()=> {
  symbolArray.push(input)

}


return (

<>

{/* here a user searches for stock */}

<div class="input-group">
                <input id="searchBar" type="search" class="form-control rounded search-bar" placeholder="Enter Ticker Symbol" aria-label="Search"
                   aria-describedby="search-addon" value={input} onInput={e => setInput(e.target.value)} />
                <button type="button" class="searchButton btn p-2  bg-succ" id="searchButton" onClick={()=> {getData(); addingStuff(); }}>Quote This Stock</button>
              </div>

{/* here is my table */}
<table class='table'>
                  <thead>
                    <tr>
{/*  table  headers*/}
                      <th scope='col'>Symbol</th>
                      <th scope='col'>Current Price</th>
                      <th scope='col'>Day High</th>
                      <th scope='col'>Day Low</th>
                      <th scope='col'>Price Change</th>
                      <th scope='col'>Open Price</th>
                      <th scope='col'>Percentage Change</th>
                      <th scope='col'>Previous Close</th>
                    </tr>
                  </thead>
                  <tbody>

{/* i call the function that gets and stores the data */}

                  {getData ? 
                    dataArray.map((stock, index) => {
                      const {c, d, dp, h, l, o, pc} = stock;
                      return (
                        <tr key={index}>

{/* here is the issue where the 2 arrays clash  */}
                         <th scope='row'>{symbolArray.map((symbol, i) => { return i})}</th>
                          <td>{c}</td>
                          <td>{d}</td>
                          <td>{dp}</td>
                          <td>{h}</td>
                          <td>{l}</td>
                          <td>{o}</td>
                          <td>{pc}</td>
                        </tr>
                      )
                    })
  
                     : null }


</>

}



When you use a library/framework like React, it's best to decouple the presentation from the control.当您使用像 React 这样的库/框架时,最好将演示文稿与控件分离。 In your case this means:在您的情况下,这意味着:

  • the table is the presentation.桌子是演示文稿。 It should have no clue where the data comes from (from a symbolArray or from a dataArray - or both).它应该不知道数据来自哪里(来自symbolArray或来自dataArray - 或两者)。
  • the symbolArray , the dataArray and their union is the control. symbolArraydataArray和它们的联合是控件。 This doesn't need to "know" how the data is presented (it could be an ordered/unordered list, a table or a simple data iterator displayed as a card element).这不需要“知道”数据是如何呈现的(它可以是有序/无序列表、表格或显示为卡片元素的简单数据迭代器)。

With this in mind, I think you should slice your solution in two parts:考虑到这一点,我认为您应该将解决方案分为两部分:

  • one part is responsible for getting & handling the data一部分负责获取和处理数据
  • the other part is responsible for displaying a set of data in a table.另一部分负责在表格中显示一组数据。

Here's a snippet that does this:这是执行此操作的代码段:

 const { useState, useEffect } = React // custom hook for mocking API data const useTypicode = () => { const [response, setResponse] = useState(null); // only runs once useEffect(() => { fetch('https://jsonplaceholder.typicode.com/users') .then(res => res.json()) .then(json => { setResponse(() => json.map(({id, name, username, email}) => ({id, name, username, email}))) }) }, []); return response; }; // AddUser doesn't know what is happening when the // button is clicked: only sends the current state // as an argument for the function it received // in props const AddUser = (props) => { const [name, setName] = useState(null) const [userName, setUserName] = useState(null) const [email, setEmail] = useState(null) return ( <div> Name: <input type="text" onInput={(e) => setName(e.target.value)}/><br /> Username: <input type="text" onInput={(e) => setUserName(e.target.value)}/><br /> Email: <input type="text" onInput={(e) => setEmail(e.target.value)}/><br /> <button onClick={() => props.addUser({name, userName, email})} > ADD USER + </button> </div> ) } // Table doesn't "know" where the data comes from // API, user created - doesn't matter const Table = (props) => { const headers = Object.keys(props.userList[0]) return ( <table> <thead> <tr> { headers.map(header => <th key={header}>{header}</th>) } </tr> </thead> <tbody> { props.userList.map(user => <tr key={user.id}>{Object.values(user).map((val, i) => <td key={user.id + i}>{val}</td>)}</tr>) } </tbody> </table> ) } // App doesn't know how the custom data is being // entered or how it is displayed - only knows // how to update the two lists it handles and // where to pass them on const App = () => { const apiUsers = useTypicode() const [users, setUsers] = useState([]) const addUser = (userData) => { setUsers(prevState => [ ...prevState, { id: Date.now(), ...userData } ]) } return ( <div> <AddUser addUser={(userData) => addUser(userData)} /><br /> { apiUsers && <Table userList={[...apiUsers, ...users]} /> } </div> ) } ReactDOM.render( <App />, document.getElementById('root') );
 <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <div id="root"></div>

Sorry for some "bad practice" in the snippet (eg defining functions in the JSX elements in AddUser ), but the basic logic is what I wanted to illustrate: don't think of the HTML table as an entity that stores anything.很抱歉片段中的一些“不好的做法”(例如在AddUser的 JSX 元素中定义函数),但基本逻辑是我想说明的:不要将 HTML 表视为存储任何内容的实体。 No, the HTML table only displays what you feed it with.不,HTML 表格只显示您提供给它的内容。 "Play" with the data in JS (merge different sources, filter by key/value, sort, etc.), and the presentation (table) should update (because it's fed with a new set of data it can display).在 JS 中“播放”数据(合并不同的源,按键/值过滤,排序等),并且演示文稿(表格)应该更新(因为它提供了一组可以显示的新数据)。 This is reactivity.这是反应性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM